jazzy 0.13.7 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/Tests.yml +2 -2
- data/.rubocop.yml +123 -24
- data/CHANGELOG.md +34 -0
- data/Dangerfile +11 -8
- data/Gemfile +3 -1
- data/Gemfile.lock +49 -34
- data/README.md +23 -11
- data/Rakefile +13 -12
- data/bin/jazzy +3 -2
- data/jazzy.gemspec +8 -6
- data/lib/jazzy.rb +2 -0
- data/lib/jazzy/config.rb +116 -69
- data/lib/jazzy/doc.rb +3 -1
- data/lib/jazzy/doc_builder.rb +63 -81
- 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 +63 -30
- data/lib/jazzy/podspec_documenter.rb +14 -16
- data/lib/jazzy/search_builder.rb +4 -3
- data/lib/jazzy/source_declaration.rb +9 -3
- data/lib/jazzy/source_declaration/access_control_level.rb +7 -5
- data/lib/jazzy/source_declaration/type.rb +3 -1
- 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 +98 -72
- data/lib/jazzy/stats.rb +4 -2
- data/lib/jazzy/symbol_graph.rb +15 -15
- 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 +13 -11
- data/lib/jazzy/symbol_graph/relationship.rb +3 -0
- data/lib/jazzy/symbol_graph/sym_node.rb +11 -6
- data/lib/jazzy/symbol_graph/symbol.rb +18 -15
- 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 +3 -3
- data/lib/jazzy/themes/apple/templates/footer.mustache +1 -1
- data/lib/jazzy/themes/apple/templates/header.mustache +3 -3
- data/lib/jazzy/themes/apple/templates/task.mustache +3 -3
- 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 +3 -3
- data/lib/jazzy/themes/fullwidth/templates/footer.mustache +1 -1
- data/lib/jazzy/themes/fullwidth/templates/header.mustache +5 -5
- data/lib/jazzy/themes/fullwidth/templates/task.mustache +3 -3
- 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 +3 -3
- data/lib/jazzy/themes/jony/templates/footer.mustache +1 -1
- data/lib/jazzy/themes/jony/templates/header.mustache +5 -5
- data/lib/jazzy/themes/jony/templates/task.mustache +3 -3
- data/spec/integration_spec.rb +39 -36
- data/spec/spec_helper.rb +3 -1
- data/spec/spec_helper/pre_flight.rb +2 -0
- metadata +27 -13
- 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
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'tmpdir'
|
2
4
|
require 'json'
|
3
5
|
|
@@ -22,8 +24,8 @@ module Jazzy
|
|
22
24
|
installer.install!
|
23
25
|
stdout = Dir.chdir(sandbox.root) do
|
24
26
|
targets = installer.pod_targets
|
25
|
-
|
26
|
-
|
27
|
+
.select { |pt| pt.pod_name == podspec.root.name }
|
28
|
+
.map(&:label)
|
27
29
|
|
28
30
|
targets.map do |t|
|
29
31
|
args = %W[doc --module-name #{podspec.module_name} -- -target #{t}]
|
@@ -42,8 +44,6 @@ module Jazzy
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
45
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
46
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
47
47
|
# rubocop:disable Metrics/MethodLength
|
48
48
|
def self.apply_config_defaults(podspec, config)
|
49
49
|
return unless podspec
|
@@ -64,9 +64,9 @@ module Jazzy
|
|
64
64
|
config.version = podspec.version.to_s
|
65
65
|
config.version_configured = true
|
66
66
|
end
|
67
|
-
unless config.
|
68
|
-
config.
|
69
|
-
config.
|
67
|
+
unless config.source_host_files_url_configured
|
68
|
+
config.source_host_files_url = github_file_prefix(podspec)
|
69
|
+
config.source_host_files_url_configured = true
|
70
70
|
end
|
71
71
|
unless config.swift_version_configured
|
72
72
|
trunk_swift_build = podspec.attributes_hash['pushed_with_swift_version']
|
@@ -74,8 +74,6 @@ module Jazzy
|
|
74
74
|
config.swift_version_configured = true
|
75
75
|
end
|
76
76
|
end
|
77
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
78
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
79
77
|
# rubocop:enable Metrics/MethodLength
|
80
78
|
|
81
79
|
private
|
@@ -94,17 +92,17 @@ module Jazzy
|
|
94
92
|
|
95
93
|
def self.github_file_prefix(podspec)
|
96
94
|
return unless podspec.source[:url] =~ %r{github.com[:/]+(.+)/(.+)}
|
95
|
+
|
97
96
|
org, repo = Regexp.last_match
|
98
|
-
return unless org && repo
|
99
|
-
repo.sub!(/\.git$/, '')
|
100
97
|
return unless rev = podspec.source[:tag] || podspec.source[:commit]
|
101
|
-
|
98
|
+
|
99
|
+
"https://github.com/#{org}/#{repo.sub(/\.git$/, '')}/blob/#{rev}"
|
102
100
|
end
|
103
101
|
|
104
102
|
private_class_method :github_file_prefix
|
105
103
|
|
106
104
|
# Latest valid value for SWIFT_VERSION.
|
107
|
-
LATEST_SWIFT_VERSION = '5'
|
105
|
+
LATEST_SWIFT_VERSION = '5'
|
108
106
|
|
109
107
|
# All valid values for SWIFT_VERSION that are longer
|
110
108
|
# than a major version number. Ordered ascending.
|
@@ -162,9 +160,8 @@ module Jazzy
|
|
162
160
|
# Travis builds take too long when building docs for all available
|
163
161
|
# platforms for the Moya integration spec, so we just document OSX.
|
164
162
|
# TODO: remove once jazzy is fast enough.
|
165
|
-
if ENV['JAZZY_INTEGRATION_SPECS']
|
166
|
-
|
167
|
-
end
|
163
|
+
next if ENV['JAZZY_INTEGRATION_SPECS'] && p.name != :osx
|
164
|
+
|
168
165
|
target("Jazzy-#{ss.name.gsub('/', '__')}-#{p.name}") do
|
169
166
|
use_frameworks!
|
170
167
|
platform p.name, p.deployment_target
|
@@ -177,4 +174,5 @@ module Jazzy
|
|
177
174
|
end
|
178
175
|
# rubocop:enable Metrics/MethodLength
|
179
176
|
end
|
177
|
+
# rubocop:enable Metrics/ClassLength
|
180
178
|
end
|
data/lib/jazzy/search_builder.rb
CHANGED
@@ -1,18 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Jazzy
|
2
4
|
module SearchBuilder
|
3
5
|
def self.build(source_module, output_dir)
|
4
6
|
decls = source_module.all_declarations.select do |d|
|
5
7
|
d.type && d.name && !d.name.empty?
|
6
8
|
end
|
7
|
-
index =
|
9
|
+
index = decls.map do |d|
|
8
10
|
[d.url,
|
9
11
|
{
|
10
12
|
name: d.name,
|
11
13
|
abstract: d.abstract && d.abstract.split(/\n/).map(&:strip).first,
|
12
14
|
parent_name: d.parent_in_code && d.parent_in_code.name,
|
13
15
|
}.reject { |_, v| v.nil? || v.empty? }]
|
14
|
-
end
|
15
|
-
]
|
16
|
+
end.to_h
|
16
17
|
File.open(File.join(output_dir, 'search.json'), 'w') do |f|
|
17
18
|
f.write(index.to_json)
|
18
19
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'jazzy/source_declaration/access_control_level'
|
2
4
|
require 'jazzy/source_declaration/type'
|
3
5
|
|
4
|
-
# rubocop:disable Metrics/ClassLength
|
5
6
|
module Jazzy
|
7
|
+
# rubocop:disable Metrics/ClassLength
|
6
8
|
class SourceDeclaration
|
7
9
|
# kind of declaration (e.g. class, variable, function)
|
8
10
|
attr_accessor :type
|
@@ -39,7 +41,7 @@ module Jazzy
|
|
39
41
|
attr_accessor :parent_in_docs
|
40
42
|
|
41
43
|
# counterpart of parent_in_docs
|
42
|
-
|
44
|
+
attr_reader :children
|
43
45
|
|
44
46
|
def children=(new_children)
|
45
47
|
# Freeze to ensure that parent_in_docs stays in sync
|
@@ -76,7 +78,7 @@ module Jazzy
|
|
76
78
|
# of the extended objc class and the category name itself, i.e.
|
77
79
|
# ["NSString", "MyMethods"], nil otherwise.
|
78
80
|
def objc_category_name
|
79
|
-
name.split(/[
|
81
|
+
name.split(/[()]/) if type.objc_category?
|
80
82
|
end
|
81
83
|
|
82
84
|
def swift_objc_extension?
|
@@ -151,6 +153,7 @@ module Jazzy
|
|
151
153
|
# Workaround functions sharing names with
|
152
154
|
# different argument types (f(a:Int) vs. f(a:String))
|
153
155
|
return result unless type.swift_global_function?
|
156
|
+
|
154
157
|
result + "_#{type_usr}"
|
155
158
|
end
|
156
159
|
|
@@ -175,6 +178,7 @@ module Jazzy
|
|
175
178
|
# Is there at least one inherited type that is not in the given list?
|
176
179
|
def other_inherited_types?(unwanted)
|
177
180
|
return false unless inherited_types?
|
181
|
+
|
178
182
|
inherited_types.any? { |t| !unwanted.include?(t) }
|
179
183
|
end
|
180
184
|
|
@@ -201,7 +205,9 @@ module Jazzy
|
|
201
205
|
return [] unless
|
202
206
|
Config.instance.abstract_glob_configured &&
|
203
207
|
Config.instance.abstract_glob
|
208
|
+
|
204
209
|
Config.instance.abstract_glob.select { |e| File.file? e }
|
205
210
|
end
|
206
211
|
end
|
212
|
+
# rubocop:enable Metrics/ClassLength
|
207
213
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Jazzy
|
2
4
|
class SourceDeclaration
|
3
5
|
class AccessControlLevel
|
@@ -5,12 +7,12 @@ module Jazzy
|
|
5
7
|
|
6
8
|
attr_reader :level
|
7
9
|
|
8
|
-
ACCESSIBILITY_PRIVATE = 'source.lang.swift.accessibility.private'
|
10
|
+
ACCESSIBILITY_PRIVATE = 'source.lang.swift.accessibility.private'
|
9
11
|
ACCESSIBILITY_FILEPRIVATE =
|
10
|
-
'source.lang.swift.accessibility.fileprivate'
|
11
|
-
ACCESSIBILITY_INTERNAL = 'source.lang.swift.accessibility.internal'
|
12
|
-
ACCESSIBILITY_PUBLIC = 'source.lang.swift.accessibility.public'
|
13
|
-
ACCESSIBILITY_OPEN = 'source.lang.swift.accessibility.open'
|
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'
|
14
16
|
|
15
17
|
def initialize(accessibility)
|
16
18
|
@level = case accessibility
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/inflector'
|
2
4
|
|
3
5
|
module Jazzy
|
@@ -151,7 +153,7 @@ module Jazzy
|
|
151
153
|
Type.new('Overview')
|
152
154
|
end
|
153
155
|
|
154
|
-
MARKDOWN_KIND = 'document.markdown'
|
156
|
+
MARKDOWN_KIND = 'document.markdown'
|
155
157
|
|
156
158
|
def self.markdown
|
157
159
|
Type.new(MARKDOWN_KIND)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'pathname'
|
2
4
|
|
3
5
|
require 'jazzy/jazzy_markdown'
|
@@ -43,6 +45,7 @@ module Jazzy
|
|
43
45
|
|
44
46
|
def content(source_module)
|
45
47
|
return readme_content(source_module) if name == 'index'
|
48
|
+
|
46
49
|
overview
|
47
50
|
end
|
48
51
|
|
@@ -51,7 +54,7 @@ module Jazzy
|
|
51
54
|
end
|
52
55
|
|
53
56
|
def config_readme
|
54
|
-
readme_path.read if readme_path
|
57
|
+
readme_path.read if readme_path&.exist?
|
55
58
|
end
|
56
59
|
|
57
60
|
def fallback_readme
|
@@ -67,7 +70,7 @@ module Jazzy
|
|
67
70
|
### License
|
68
71
|
|
69
72
|
# <a href="#{license[:url]}">#{license[:license]}</a>
|
70
|
-
<<-
|
73
|
+
<<-README
|
71
74
|
# #{podspec.name}
|
72
75
|
|
73
76
|
### #{podspec.summary}
|
@@ -83,15 +86,15 @@ pod '#{podspec.name}'
|
|
83
86
|
### Authors
|
84
87
|
|
85
88
|
#{source_module.author_name}
|
86
|
-
|
89
|
+
README
|
87
90
|
else
|
88
|
-
<<-
|
91
|
+
<<-README
|
89
92
|
# #{source_module.name}
|
90
93
|
|
91
94
|
### Authors
|
92
95
|
|
93
96
|
#{source_module.author_name}
|
94
|
-
|
97
|
+
README
|
95
98
|
end
|
96
99
|
end
|
97
100
|
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jazzy
|
4
|
+
# Deal with different source code repositories
|
5
|
+
module SourceHost
|
6
|
+
# Factory to create the right source host
|
7
|
+
def self.create(options)
|
8
|
+
return unless options.source_host_url || options.source_host_files_url
|
9
|
+
|
10
|
+
case options.source_host
|
11
|
+
when :github then GitHub.new
|
12
|
+
when :gitlab then GitLab.new
|
13
|
+
when :bitbucket then BitBucket.new
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Use GitHub as the default behaviour.
|
18
|
+
class GitHub
|
19
|
+
include Config::Mixin
|
20
|
+
|
21
|
+
# Human readable name, appears in UI
|
22
|
+
def name
|
23
|
+
'GitHub'
|
24
|
+
end
|
25
|
+
|
26
|
+
# Jazzy extension with logo
|
27
|
+
def extension
|
28
|
+
name.downcase
|
29
|
+
end
|
30
|
+
|
31
|
+
# Logo image filename within extension
|
32
|
+
def image
|
33
|
+
'gh.png'
|
34
|
+
end
|
35
|
+
|
36
|
+
# URL to link to from logo
|
37
|
+
def url
|
38
|
+
config.source_host_url
|
39
|
+
end
|
40
|
+
|
41
|
+
# URL to link to from a SourceDeclaration.
|
42
|
+
# Compare using `realpath` because `item.file` comes out of
|
43
|
+
# SourceKit/etc.
|
44
|
+
def item_url(item)
|
45
|
+
return unless files_url && item.file
|
46
|
+
|
47
|
+
realpath = item.file.realpath
|
48
|
+
return unless realpath.to_path.start_with?(local_root_realpath)
|
49
|
+
|
50
|
+
path = realpath.relative_path_from(local_root_realpath)
|
51
|
+
fragment =
|
52
|
+
if item.start_line && (item.start_line != item.end_line)
|
53
|
+
item_url_multiline_fragment(item.start_line, item.end_line)
|
54
|
+
else
|
55
|
+
item_url_line_fragment(item.line)
|
56
|
+
end
|
57
|
+
|
58
|
+
"#{files_url}/#{path}##{fragment}"
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def files_url
|
64
|
+
config.source_host_files_url
|
65
|
+
end
|
66
|
+
|
67
|
+
def local_root_realpath
|
68
|
+
@local_root_realpath ||= config.source_directory.realpath.to_path
|
69
|
+
end
|
70
|
+
|
71
|
+
# Source host's line numbering link scheme
|
72
|
+
def item_url_line_fragment(line)
|
73
|
+
"L#{line}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def item_url_multiline_fragment(start_line, end_line)
|
77
|
+
"L#{start_line}-L#{end_line}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# GitLab very similar to GitHub
|
82
|
+
class GitLab < GitHub
|
83
|
+
def name
|
84
|
+
'GitLab'
|
85
|
+
end
|
86
|
+
|
87
|
+
def image
|
88
|
+
'gitlab.svg'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# BitBucket has its own line number system
|
93
|
+
class BitBucket < GitHub
|
94
|
+
def name
|
95
|
+
'Bitbucket'
|
96
|
+
end
|
97
|
+
|
98
|
+
def image
|
99
|
+
'bitbucket.svg'
|
100
|
+
end
|
101
|
+
|
102
|
+
def item_url_line_fragment(line)
|
103
|
+
"lines-#{line}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def item_url_multiline_fragment(start_line, end_line)
|
107
|
+
"lines-#{start_line}:#{end_line}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/lib/jazzy/source_mark.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Jazzy
|
2
4
|
class SourceMark
|
3
5
|
attr_accessor :name
|
@@ -8,24 +10,24 @@ module Jazzy
|
|
8
10
|
return unless mark_string
|
9
11
|
|
10
12
|
# Format: 'MARK: - NAME -' with dashes optional
|
11
|
-
mark_string.sub
|
13
|
+
mark_content = mark_string.sub(/^MARK: /, '')
|
12
14
|
|
13
|
-
if
|
15
|
+
if mark_content.empty?
|
14
16
|
# Empty
|
15
17
|
return
|
16
|
-
elsif
|
18
|
+
elsif mark_content == '-'
|
17
19
|
# Separator
|
18
20
|
self.has_start_dash = true
|
19
21
|
return
|
20
22
|
end
|
21
23
|
|
22
|
-
self.has_start_dash =
|
23
|
-
self.has_end_dash =
|
24
|
+
self.has_start_dash = mark_content.start_with?('- ')
|
25
|
+
self.has_end_dash = mark_content.end_with?(' -')
|
24
26
|
|
25
27
|
start_index = has_start_dash ? 2 : 0
|
26
28
|
end_index = has_end_dash ? -3 : -1
|
27
29
|
|
28
|
-
self.name =
|
30
|
+
self.name = mark_content[start_index..end_index]
|
29
31
|
end
|
30
32
|
|
31
33
|
def self.new_generic_requirements(requirements)
|
data/lib/jazzy/source_module.rb
CHANGED
@@ -1,32 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
|
3
5
|
require 'jazzy/config'
|
4
6
|
require 'jazzy/source_declaration'
|
7
|
+
require 'jazzy/source_host'
|
5
8
|
|
6
9
|
module Jazzy
|
7
10
|
class SourceModule
|
8
11
|
attr_accessor :name
|
9
|
-
attr_accessor :root_path
|
10
12
|
attr_accessor :docs
|
11
13
|
attr_accessor :doc_coverage
|
12
14
|
attr_accessor :doc_structure
|
13
15
|
attr_accessor :author_name
|
14
|
-
attr_accessor :github_url
|
15
|
-
attr_accessor :github_file_prefix
|
16
16
|
attr_accessor :author_url
|
17
17
|
attr_accessor :dash_url
|
18
|
+
attr_accessor :host
|
18
19
|
|
19
20
|
def initialize(options, docs, doc_structure, doc_coverage)
|
20
21
|
self.docs = docs
|
21
|
-
self.root_path = options.source_directory
|
22
22
|
self.doc_structure = doc_structure
|
23
23
|
self.doc_coverage = doc_coverage
|
24
24
|
self.name = options.module_name
|
25
25
|
self.author_name = options.author_name
|
26
|
-
self.github_url = options.github_url
|
27
|
-
self.github_file_prefix = options.github_file_prefix
|
28
26
|
self.author_url = options.author_url
|
27
|
+
self.host = SourceHost.create(options)
|
29
28
|
return unless options.dash_url
|
29
|
+
|
30
30
|
self.dash_url =
|
31
31
|
"dash-feed://#{ERB::Util.url_encode(options.dash_url.to_s)}"
|
32
32
|
end
|
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,8 +272,6 @@ 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 = []
|
@@ -278,13 +279,12 @@ module Jazzy
|
|
278
279
|
|
279
280
|
def self.availability_attribute?(doc)
|
280
281
|
return false unless doc['key.attributes']
|
282
|
+
|
281
283
|
!doc['key.attributes'].select do |attribute|
|
282
284
|
attribute.values.first == 'source.decl.attribute.available'
|
283
285
|
end.empty?
|
284
286
|
end
|
285
287
|
|
286
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
287
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
288
288
|
def self.should_document?(doc)
|
289
289
|
return false if doc['key.doc.comment'].to_s.include?(':nodoc:')
|
290
290
|
|
@@ -314,8 +314,6 @@ module Jazzy
|
|
314
314
|
end
|
315
315
|
acl_ok
|
316
316
|
end
|
317
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
318
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
319
317
|
|
320
318
|
def self.should_document_swift_extension?(doc)
|
321
319
|
doc['key.inheritedtypes'] ||
|
@@ -337,6 +335,7 @@ module Jazzy
|
|
337
335
|
if !declaration.swift? || should_mark_undocumented(declaration)
|
338
336
|
@stats.add_undocumented(declaration)
|
339
337
|
return nil if @skip_undocumented
|
338
|
+
|
340
339
|
declaration.abstract = undocumented_abstract
|
341
340
|
else
|
342
341
|
declaration.abstract = Markdown.render(doc['key.doc.comment'] || '',
|
@@ -404,7 +403,7 @@ module Jazzy
|
|
404
403
|
def self.xml_to_text(xml)
|
405
404
|
document = REXML::Document.new(xml)
|
406
405
|
REXML::XPath.match(document.root, '//text()').map(&:value).join
|
407
|
-
rescue
|
406
|
+
rescue StandardError
|
408
407
|
''
|
409
408
|
end
|
410
409
|
|
@@ -490,11 +489,10 @@ module Jazzy
|
|
490
489
|
end
|
491
490
|
|
492
491
|
# @available attrs only in compiler 'interface' style
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
.join("\n")
|
492
|
+
extract_availability(doc['key.doc.declaration'] || '')
|
493
|
+
.concat(extract_attributes(annotated_decl_attrs))
|
494
|
+
.push(decl)
|
495
|
+
.join("\n")
|
498
496
|
end
|
499
497
|
|
500
498
|
# Strip default property attributes because libclang
|
@@ -510,12 +508,14 @@ module Jazzy
|
|
510
508
|
attrs = Regexp.last_match[1].split(',').map(&:strip) - DEFAULT_ATTRIBUTES
|
511
509
|
attrs_text = attrs.empty? ? '' : " (#{attrs.join(', ')})"
|
512
510
|
|
513
|
-
declaration
|
514
|
-
|
511
|
+
declaration
|
512
|
+
.sub(/(?<=@property)\s+\(.*?\)/, attrs_text)
|
513
|
+
.gsub(/\s+/, ' ')
|
515
514
|
end
|
516
515
|
|
517
516
|
def self.make_substructure(doc, declaration)
|
518
517
|
return [] unless subdocs = doc['key.substructure']
|
518
|
+
|
519
519
|
make_source_declarations(subdocs,
|
520
520
|
declaration,
|
521
521
|
declaration.mark_for_children)
|
@@ -558,8 +558,8 @@ module Jazzy
|
|
558
558
|
|
559
559
|
unless declaration.type.name
|
560
560
|
raise 'Please file an issue at ' \
|
561
|
-
|
562
|
-
|
561
|
+
'https://github.com/realm/jazzy/issues about adding support ' \
|
562
|
+
"for `#{declaration.type.kind}`."
|
563
563
|
end
|
564
564
|
|
565
565
|
declaration.file = Pathname(doc['key.filepath']) if doc['key.filepath']
|
@@ -570,8 +570,8 @@ module Jazzy
|
|
570
570
|
declaration.mark = current_mark
|
571
571
|
declaration.access_control_level =
|
572
572
|
SourceDeclaration::AccessControlLevel.from_doc(doc)
|
573
|
-
declaration.line = doc['key.doc.line']
|
574
|
-
declaration.column = doc['key.doc.column']
|
573
|
+
declaration.line = doc['key.doc.line'] || doc['key.line']
|
574
|
+
declaration.column = doc['key.doc.column'] || doc['key.column']
|
575
575
|
declaration.start_line = doc['key.parsed_scope.start']
|
576
576
|
declaration.end_line = doc['key.parsed_scope.end']
|
577
577
|
declaration.deprecated = doc['key.always_deprecated']
|
@@ -583,10 +583,12 @@ module Jazzy
|
|
583
583
|
inherited_types.map { |type| type['key.name'] }.compact
|
584
584
|
|
585
585
|
next unless make_doc_info(doc, declaration)
|
586
|
+
|
586
587
|
declaration.children = make_substructure(doc, declaration)
|
587
588
|
next if declaration.type.extension? &&
|
588
589
|
declaration.children.empty? &&
|
589
590
|
!declaration.inherited_types?
|
591
|
+
|
590
592
|
declarations << declaration
|
591
593
|
end
|
592
594
|
declarations
|
@@ -598,6 +600,7 @@ module Jazzy
|
|
598
600
|
def self.find_generic_requirements(parsed_declaration)
|
599
601
|
parsed_declaration =~ /\bwhere\s+(.*)$/m
|
600
602
|
return nil unless Regexp.last_match
|
603
|
+
|
601
604
|
Regexp.last_match[1].gsub(/\s+/, ' ')
|
602
605
|
end
|
603
606
|
|
@@ -619,6 +622,7 @@ module Jazzy
|
|
619
622
|
|
620
623
|
def self.expand_extension(extension, name_parts, decls)
|
621
624
|
return extension if name_parts.empty?
|
625
|
+
|
622
626
|
name = name_parts.shift
|
623
627
|
candidates = decls.select { |decl| decl.name == name }
|
624
628
|
SourceDeclaration.new.tap do |decl|
|
@@ -644,8 +648,8 @@ module Jazzy
|
|
644
648
|
# Merges redundant declarations when documenting podspecs.
|
645
649
|
def self.deduplicate_declarations(declarations)
|
646
650
|
duplicate_groups = declarations
|
647
|
-
|
648
|
-
|
651
|
+
.group_by { |d| deduplication_key(d, declarations) }
|
652
|
+
.values
|
649
653
|
|
650
654
|
duplicate_groups.flat_map do |group|
|
651
655
|
# Put extended type (if present) before extensions
|
@@ -688,15 +692,17 @@ module Jazzy
|
|
688
692
|
end
|
689
693
|
|
690
694
|
# rubocop:disable Metrics/MethodLength
|
695
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
691
696
|
# Merges all of the given types and extensions into a single document.
|
692
697
|
def self.merge_declarations(decls)
|
693
698
|
extensions, typedecls = decls.partition { |d| d.type.extension? }
|
694
699
|
|
695
700
|
if typedecls.size > 1
|
701
|
+
info = typedecls
|
702
|
+
.map { |t| "#{t.type.name.downcase} #{t.name}" }
|
703
|
+
.join(', ')
|
696
704
|
warn 'Found conflicting type declarations with the same name, which ' \
|
697
|
-
|
698
|
-
typedecls.map { |t| "#{t.type.name.downcase} #{t.name}" }
|
699
|
-
.join(', ')
|
705
|
+
"may indicate a build issue or a bug in Jazzy: #{info}"
|
700
706
|
end
|
701
707
|
typedecl = typedecls.first
|
702
708
|
|
@@ -712,13 +718,14 @@ module Jazzy
|
|
712
718
|
end
|
713
719
|
|
714
720
|
# Keep type-aliases separate from any extensions
|
715
|
-
if typedecl
|
721
|
+
if typedecl&.type&.swift_typealias?
|
716
722
|
[merge_type_and_extensions(typedecls, []),
|
717
723
|
merge_type_and_extensions([], extensions)]
|
718
724
|
else
|
719
725
|
merge_type_and_extensions(typedecls, extensions)
|
720
726
|
end
|
721
727
|
end
|
728
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
722
729
|
# rubocop:enable Metrics/MethodLength
|
723
730
|
|
724
731
|
def self.merge_type_and_extensions(typedecls, extensions)
|
@@ -810,6 +817,7 @@ module Jazzy
|
|
810
817
|
# (unless they already have a mark)
|
811
818
|
def self.merge_objc_declaration_marks(typedecl, extensions)
|
812
819
|
return unless typedecl.type.objc_class?
|
820
|
+
|
813
821
|
extensions.each do |ext|
|
814
822
|
_, category_name = ext.objc_category_name
|
815
823
|
ext.children.each { |c| c.mark.name ||= category_name }
|
@@ -819,7 +827,8 @@ module Jazzy
|
|
819
827
|
# For each extension to be merged, move any MARK from the extension
|
820
828
|
# declaration down to the extension contents so it still shows up.
|
821
829
|
def self.move_merged_extension_marks(decls)
|
822
|
-
return unless to_be_merged = decls[1
|
830
|
+
return unless to_be_merged = decls[1..]
|
831
|
+
|
823
832
|
to_be_merged.each do |ext|
|
824
833
|
child = ext.children.first
|
825
834
|
if child && child.mark.empty?
|
@@ -834,7 +843,7 @@ module Jazzy
|
|
834
843
|
def self.merge_code_declaration(decls)
|
835
844
|
first = decls.first
|
836
845
|
|
837
|
-
declarations = decls[1
|
846
|
+
declarations = decls[1..].select do |decl|
|
838
847
|
decl.type.swift_extension? &&
|
839
848
|
(decl.other_inherited_types?(@inaccessible_protocols) ||
|
840
849
|
(first.type.swift_extension? && decl.constrained_extension?))
|
@@ -879,9 +888,11 @@ module Jazzy
|
|
879
888
|
|
880
889
|
def self.name_match(name_part, docs)
|
881
890
|
return nil unless name_part
|
891
|
+
|
882
892
|
wildcard_expansion = Regexp.escape(name_part)
|
883
|
-
|
884
|
-
|
893
|
+
.gsub('\.\.\.', '[^)]*')
|
894
|
+
.gsub(/<.*>/, '')
|
895
|
+
|
885
896
|
whole_name_pat = /\A#{wildcard_expansion}\Z/
|
886
897
|
docs.find do |doc|
|
887
898
|
whole_name_pat =~ doc.name
|
@@ -911,19 +922,26 @@ module Jazzy
|
|
911
922
|
# - method signatures after they've been processed by the highlighter
|
912
923
|
#
|
913
924
|
# The `after_highlight` flag is used to differentiate between the two modes.
|
914
|
-
|
925
|
+
#
|
926
|
+
# DocC link format - follow Xcode and don't display slash-separated parts.
|
927
|
+
# rubocop:disable Metrics/MethodLength
|
928
|
+
def self.autolink_text(text, doc, root_decls, after_highlight: false)
|
915
929
|
text.autolink_block(doc.url, '[^\s]+', after_highlight) do |raw_name|
|
916
|
-
|
917
|
-
|
918
|
-
|
930
|
+
sym_name =
|
931
|
+
(raw_name[/^<doc:(.*)>$/, 1] || raw_name).sub(/(?<!^)-.+$/, '')
|
932
|
+
|
933
|
+
parts = sym_name
|
934
|
+
.sub(/^@/, '') # ignore for custom attribute ref
|
935
|
+
.split(%r{(?<!\.)[/.](?!\.)}) # dot or slash, but not '...'
|
936
|
+
.reject(&:empty?)
|
919
937
|
|
920
938
|
# First dot-separated component can match any ancestor or top-level doc
|
921
939
|
first_part = parts.shift
|
922
940
|
name_root = ancestor_name_match(first_part, doc) ||
|
923
941
|
name_match(first_part, root_decls)
|
924
942
|
|
925
|
-
# Traverse children via
|
926
|
-
name_traversal(parts, name_root)
|
943
|
+
# Traverse children via subsequent components, if any
|
944
|
+
[name_traversal(parts, name_root), sym_name.sub(%r{^.*/}, '')]
|
927
945
|
end.autolink_block(doc.url, '[+-]\[\w+(?: ?\(\w+\))? [\w:]+\]',
|
928
946
|
after_highlight) do |raw_name|
|
929
947
|
match = raw_name.match(/([+-])\[(\w+(?: ?\(\w+\))?) ([\w:]+)\]/)
|
@@ -935,42 +953,50 @@ module Jazzy
|
|
935
953
|
|
936
954
|
if name_root
|
937
955
|
# Look up the verb in the subject’s children
|
938
|
-
name_match(match[1] + match[3], name_root.children)
|
956
|
+
[name_match(match[1] + match[3], name_root.children), raw_name]
|
939
957
|
end
|
940
958
|
end.autolink_block(doc.url, '[+-]\w[\w:]*', after_highlight) do |raw_name|
|
941
|
-
name_match(raw_name, doc.children)
|
959
|
+
[name_match(raw_name, doc.children), raw_name]
|
942
960
|
end
|
943
961
|
end
|
962
|
+
# rubocop:enable Metrics/MethodLength
|
944
963
|
|
945
964
|
AUTOLINK_TEXT_FIELDS = %w[return
|
946
965
|
abstract
|
947
966
|
unavailable_message
|
948
967
|
deprecation_message].freeze
|
949
968
|
|
969
|
+
def self.autolink_text_fields(doc, root_decls)
|
970
|
+
AUTOLINK_TEXT_FIELDS.each do |field|
|
971
|
+
if text = doc.send(field)
|
972
|
+
doc.send(field + '=', autolink_text(text, doc, root_decls))
|
973
|
+
end
|
974
|
+
end
|
975
|
+
|
976
|
+
(doc.parameters || []).each do |param|
|
977
|
+
param[:discussion] =
|
978
|
+
autolink_text(param[:discussion], doc, root_decls)
|
979
|
+
end
|
980
|
+
end
|
981
|
+
|
950
982
|
AUTOLINK_HIGHLIGHT_FIELDS = %w[declaration
|
951
983
|
other_language_declaration].freeze
|
952
984
|
|
985
|
+
def self.autolink_highlight_fields(doc, root_decls)
|
986
|
+
AUTOLINK_HIGHLIGHT_FIELDS.each do |field|
|
987
|
+
if text = doc.send(field)
|
988
|
+
doc.send(field + '=',
|
989
|
+
autolink_text(text, doc, root_decls, after_highlight: true))
|
990
|
+
end
|
991
|
+
end
|
992
|
+
end
|
993
|
+
|
953
994
|
def self.autolink(docs, root_decls)
|
954
995
|
@autolink_root_decls = root_decls
|
955
996
|
docs.each do |doc|
|
956
997
|
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
|
998
|
+
autolink_text_fields(doc, root_decls)
|
999
|
+
autolink_highlight_fields(doc, root_decls)
|
974
1000
|
end
|
975
1001
|
end
|
976
1002
|
|