jazzy 0.14.3 → 0.14.4

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.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jazzy
4
- VERSION = '0.14.3' unless defined? Jazzy::VERSION
4
+ VERSION = '0.14.4' unless defined? Jazzy::VERSION
5
5
  end
@@ -10,7 +10,7 @@ module Jazzy
10
10
  [d.url,
11
11
  {
12
12
  name: d.name,
13
- abstract: d.abstract && d.abstract.split(/\n/).map(&:strip).first,
13
+ abstract: d.abstract && d.abstract.split("\n").map(&:strip).first,
14
14
  parent_name: d.parent_in_code&.name,
15
15
  }.reject { |_, v| v.nil? || v.empty? }]
16
16
  end
@@ -5,106 +5,94 @@ module Jazzy
5
5
  class AccessControlLevel
6
6
  include Comparable
7
7
 
8
+ # Order matters
9
+ LEVELS = %i[private fileprivate internal package public open].freeze
10
+
11
+ LEVELS_INDEX = LEVELS.to_h { |i| [i, LEVELS.index(i)] }.freeze
12
+
8
13
  attr_reader :level
9
14
 
10
- ACCESSIBILITY_PRIVATE = 'source.lang.swift.accessibility.private'
11
- ACCESSIBILITY_FILEPRIVATE =
12
- 'source.lang.swift.accessibility.fileprivate'
13
- ACCESSIBILITY_INTERNAL = 'source.lang.swift.accessibility.internal'
14
- ACCESSIBILITY_PUBLIC = 'source.lang.swift.accessibility.public'
15
- ACCESSIBILITY_OPEN = 'source.lang.swift.accessibility.open'
16
-
17
- def initialize(accessibility)
18
- @level = case accessibility
19
- when ACCESSIBILITY_PRIVATE then :private
20
- when ACCESSIBILITY_FILEPRIVATE then :fileprivate
21
- when ACCESSIBILITY_INTERNAL then :internal
22
- when ACCESSIBILITY_PUBLIC then :public
23
- when ACCESSIBILITY_OPEN then :open
24
- else
25
- raise 'cannot initialize AccessControlLevel with ' \
26
- "'#{accessibility}'"
27
- end
15
+ def initialize(level)
16
+ @level = level
17
+ end
18
+
19
+ # From a SourceKit accessibility string
20
+ def self.from_accessibility(accessibility)
21
+ return nil if accessibility.nil?
22
+
23
+ if accessibility =~ /^source\.lang\.swift\.accessibility\.(.*)$/ &&
24
+ (matched = Regexp.last_match(1).to_sym) &&
25
+ !LEVELS_INDEX[matched].nil?
26
+ return new(matched)
27
+ end
28
+
29
+ raise "cannot initialize AccessControlLevel with '#{accessibility}'"
28
30
  end
29
31
 
32
+ # From a SourceKit declaration hash
30
33
  def self.from_doc(doc)
31
34
  return AccessControlLevel.internal if implicit_deinit?(doc)
32
35
 
33
- accessibility = doc['key.accessibility']
34
- if accessibility
35
- acl = new(accessibility)
36
- if acl
37
- return acl
38
- end
39
- end
40
- acl = from_doc_explicit_declaration(doc)
41
- acl || AccessControlLevel.internal # fallback on internal ACL
36
+ from_documentation_attribute(doc) ||
37
+ from_accessibility(doc['key.accessibility']) ||
38
+ from_doc_explicit_declaration(doc) ||
39
+ AccessControlLevel.internal # fallback on internal ACL
42
40
  end
43
41
 
42
+ # Workaround `deinit` being always technically public
44
43
  def self.implicit_deinit?(doc)
45
44
  doc['key.name'] == 'deinit' &&
46
45
  from_doc_explicit_declaration(doc).nil?
47
46
  end
48
47
 
48
+ # From a Swift declaration
49
49
  def self.from_doc_explicit_declaration(doc)
50
- case doc['key.parsed_declaration']
51
- when /private\ / then private
52
- when /fileprivate\ / then fileprivate
53
- when /public\ / then public
54
- when /open\ / then open
55
- when /internal\ / then internal
50
+ declaration = doc['key.parsed_declaration']
51
+ LEVELS.each do |level|
52
+ if declaration =~ /\b#{level}\b/
53
+ return send(level)
54
+ end
56
55
  end
56
+ nil
57
57
  end
58
58
 
59
+ # From a config instruction
59
60
  def self.from_human_string(string)
60
- case string.to_s.downcase
61
- when 'private' then private
62
- when 'fileprivate' then fileprivate
63
- when 'internal' then internal
64
- when 'public' then public
65
- when 'open' then open
66
- else raise "cannot initialize AccessControlLevel with '#{string}'"
61
+ normalized = string.to_s.downcase.to_sym
62
+ if LEVELS_INDEX[normalized].nil?
63
+ raise "cannot initialize AccessControlLevel with '#{string}'"
67
64
  end
68
- end
69
-
70
- def self.private
71
- new(ACCESSIBILITY_PRIVATE)
72
- end
73
65
 
74
- def self.fileprivate
75
- new(ACCESSIBILITY_FILEPRIVATE)
66
+ send(normalized)
76
67
  end
77
68
 
78
- def self.internal
79
- new(ACCESSIBILITY_INTERNAL)
69
+ # From a @_documentation(visibility:) attribute
70
+ def self.from_documentation_attribute(doc)
71
+ if doc['key.annotated_decl'] =~ /@_documentation\(\s*visibility\s*:\s*(\w+)/
72
+ from_human_string(Regexp.last_match[1])
73
+ end
80
74
  end
81
75
 
82
- def self.public
83
- new(ACCESSIBILITY_PUBLIC)
84
- end
76
+ # Define `AccessControlLevel.public` etc.
85
77
 
86
- def self.open
87
- new(ACCESSIBILITY_OPEN)
78
+ LEVELS.each do |level|
79
+ define_singleton_method(level) do
80
+ new(level)
81
+ end
88
82
  end
89
83
 
90
- LEVELS = {
91
- private: 0,
92
- fileprivate: 1,
93
- internal: 2,
94
- public: 3,
95
- open: 4,
96
- }.freeze
84
+ # Comparing access levels
97
85
 
98
86
  def <=>(other)
99
- LEVELS[level] <=> LEVELS[other.level]
87
+ LEVELS_INDEX[level] <=> LEVELS_INDEX[other.level]
100
88
  end
101
89
 
102
90
  def included_levels
103
- LEVELS.select { |_, v| v >= LEVELS[level] }.keys
91
+ LEVELS_INDEX.select { |_, v| v >= LEVELS_INDEX[level] }.keys
104
92
  end
105
93
 
106
94
  def excluded_levels
107
- LEVELS.select { |_, v| v < LEVELS[level] }.keys
95
+ LEVELS_INDEX.select { |_, v| v < LEVELS_INDEX[level] }.keys
108
96
  end
109
97
  end
110
98
  end
@@ -456,6 +456,10 @@ module Jazzy
456
456
  jazzy: 'Associated Type',
457
457
  dash: 'Alias',
458
458
  }.freeze,
459
+ 'source.lang.swift.decl.macro' => {
460
+ jazzy: 'Macro',
461
+ dash: 'Macro',
462
+ }.freeze,
459
463
  }.freeze
460
464
  end
461
465
  # rubocop:enable Metrics/ClassLength
@@ -458,6 +458,13 @@ module Jazzy
458
458
  attrs.map { |str| str.gsub(/\)(?!\s*$)/, "\ufe5a") }
459
459
  end
460
460
 
461
+ # Keep everything except instructions to us
462
+ def self.extract_documented_attributes(declaration)
463
+ extract_attributes(declaration).reject do |attr|
464
+ attr.start_with?('@_documentation')
465
+ end
466
+ end
467
+
461
468
  def self.extract_availability(declaration)
462
469
  extract_attributes(declaration, 'available')
463
470
  end
@@ -521,7 +528,7 @@ module Jazzy
521
528
 
522
529
  # @available attrs only in compiler 'interface' style
523
530
  extract_availability(doc['key.doc.declaration'] || '')
524
- .concat(extract_attributes(annotated_decl_attrs))
531
+ .concat(extract_documented_attributes(annotated_decl_attrs))
525
532
  .push(decl)
526
533
  .join("\n")
527
534
  end
@@ -603,6 +610,14 @@ module Jazzy
603
610
  "for `#{declaration.type.kind}`."
604
611
  end
605
612
 
613
+ unless documented_name
614
+ warn 'Found a declaration without `key.name` that will be ' \
615
+ 'ignored. Documentation may be incomplete. This is probably ' \
616
+ 'caused by unresolved compiler errors: check the sourcekitten ' \
617
+ 'output for error messages.'
618
+ next
619
+ end
620
+
606
621
  declaration.file = Pathname(doc['key.filepath']) if doc['key.filepath']
607
622
  declaration.usr = doc['key.usr']
608
623
  declaration.type_usr = doc['key.typeusr']
data/lib/jazzy/stats.rb CHANGED
@@ -41,7 +41,7 @@ module Jazzy
41
41
  end
42
42
 
43
43
  def report
44
- puts "#{doc_coverage}\% documentation coverage " \
44
+ puts "#{doc_coverage}% documentation coverage " \
45
45
  "with #{undocumented} undocumented " \
46
46
  "#{symbol_or_symbols(undocumented)}"
47
47
 
@@ -70,8 +70,13 @@ module Jazzy
70
70
  end.compact
71
71
  end
72
72
 
73
- # Workaround Swift 5.3 bug with missing constraint rels
73
+ # Workaround Swift 5.3 bug with missing constraint rels, eg.
74
+ # extension P {
75
+ # func f<C>(a: C) where C: P {}
76
+ # }
74
77
  def self.new_list_from_declaration(decl)
78
+ return [] if decl.include?('(')
79
+
75
80
  decl.split(/\s*,\s*/).map { |cons| Constraint.new_declaration(cons) }
76
81
  end
77
82
 
@@ -100,6 +100,7 @@ module Jazzy
100
100
  'typealias' => 'typealias',
101
101
  'associatedtype' => 'associatedtype',
102
102
  'actor' => 'actor',
103
+ 'macro' => 'macro',
103
104
  }.freeze
104
105
 
105
106
  # We treat 'static var' differently to 'class var'
@@ -110,7 +111,7 @@ module Jazzy
110
111
  end
111
112
  return kind unless keywords.member?('static')
112
113
 
113
- kind.gsub(/type/, 'static')
114
+ kind.gsub('type', 'static')
114
115
  end
115
116
 
116
117
  def init_kind(kind, keywords)
@@ -68,7 +68,7 @@ module Jazzy
68
68
 
69
69
  # Parse the symbol files in the given directory
70
70
  def self.parse_symbols(directory)
71
- Dir[directory + '/*.symbols.json'].map do |filename|
71
+ Dir[directory + '/*.symbols.json'].sort.map do |filename|
72
72
  # The @ part is for extensions in our module (before the @)
73
73
  # of types in another module (after the @).
74
74
  File.basename(filename) =~ /(.*?)(@(.*?))?\.symbols/