jazzy 0.13.7 → 0.14.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.
- 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
|
|