jazzy 0.14.4 → 0.15.1
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 +6 -5
- data/.rubocop.yml +19 -0
- data/CHANGELOG.md +56 -0
- data/CONTRIBUTING.md +1 -1
- data/Gemfile.lock +66 -49
- data/README.md +115 -5
- data/bin/sourcekitten +0 -0
- data/jazzy.gemspec +1 -1
- data/js/package-lock.json +6 -6
- data/lib/jazzy/config.rb +156 -24
- data/lib/jazzy/doc.rb +2 -2
- data/lib/jazzy/doc_builder.rb +55 -29
- data/lib/jazzy/doc_index.rb +185 -0
- data/lib/jazzy/docset_builder/info_plist.mustache +1 -1
- data/lib/jazzy/docset_builder.rb +44 -13
- data/lib/jazzy/extensions/katex/css/katex.min.css +1 -1
- data/lib/jazzy/extensions/katex/js/katex.min.js +1 -1
- data/lib/jazzy/gem_version.rb +1 -1
- data/lib/jazzy/grouper.rb +130 -0
- data/lib/jazzy/podspec_documenter.rb +1 -1
- data/lib/jazzy/source_declaration/type.rb +10 -2
- data/lib/jazzy/source_declaration.rb +69 -8
- data/lib/jazzy/source_document.rb +5 -1
- data/lib/jazzy/source_module.rb +13 -11
- data/lib/jazzy/sourcekitten.rb +232 -236
- data/lib/jazzy/symbol_graph/ext_key.rb +37 -0
- data/lib/jazzy/symbol_graph/ext_node.rb +23 -6
- data/lib/jazzy/symbol_graph/graph.rb +31 -19
- data/lib/jazzy/symbol_graph/relationship.rb +21 -3
- data/lib/jazzy/symbol_graph/sym_node.rb +10 -22
- data/lib/jazzy/symbol_graph/symbol.rb +28 -0
- data/lib/jazzy/symbol_graph.rb +19 -16
- data/lib/jazzy/themes/apple/assets/css/jazzy.css.scss +10 -7
- data/lib/jazzy/themes/apple/assets/js/typeahead.jquery.js +3 -2
- data/lib/jazzy/themes/apple/templates/doc.mustache +8 -1
- data/lib/jazzy/themes/fullwidth/assets/css/jazzy.css.scss +5 -5
- data/lib/jazzy/themes/fullwidth/assets/js/typeahead.jquery.js +3 -2
- data/lib/jazzy/themes/fullwidth/templates/doc.mustache +8 -1
- data/lib/jazzy/themes/jony/assets/css/jazzy.css.scss +6 -5
- data/lib/jazzy/themes/jony/templates/doc.mustache +9 -2
- data/spec/integration_spec.rb +8 -1
- metadata +16 -7
data/lib/jazzy/gem_version.rb
CHANGED
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jazzy
|
4
|
+
# This module deals with arranging top-level declarations and guides into
|
5
|
+
# groups automatically and/or using a custom list.
|
6
|
+
module Grouper
|
7
|
+
extend Config::Mixin
|
8
|
+
|
9
|
+
# Group root-level docs by custom categories (if any) and type or module
|
10
|
+
def self.group_docs(docs, doc_index)
|
11
|
+
custom_categories, docs = group_custom_categories(docs, doc_index)
|
12
|
+
unlisted_prefix = config.custom_categories_unlisted_prefix
|
13
|
+
type_category_prefix = custom_categories.any? ? unlisted_prefix : ''
|
14
|
+
all_categories =
|
15
|
+
custom_categories +
|
16
|
+
if config.merge_modules == :all
|
17
|
+
group_docs_by_type(docs, type_category_prefix)
|
18
|
+
else
|
19
|
+
group_docs_by_module(docs, type_category_prefix)
|
20
|
+
end
|
21
|
+
merge_consecutive_marks(all_categories)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Group root-level docs by type
|
25
|
+
def self.group_docs_by_type(docs, type_category_prefix)
|
26
|
+
type_groups = SourceDeclaration::Type.all.map do |type|
|
27
|
+
children, docs = docs.partition { |doc| doc.type == type }
|
28
|
+
make_type_group(children, type, type_category_prefix)
|
29
|
+
end
|
30
|
+
merge_categories(type_groups.compact) + docs
|
31
|
+
end
|
32
|
+
|
33
|
+
# Group root-level docs by module name
|
34
|
+
def self.group_docs_by_module(docs, type_category_prefix)
|
35
|
+
guide_categories, docs = group_guides(docs, type_category_prefix)
|
36
|
+
|
37
|
+
module_categories = docs
|
38
|
+
.group_by(&:doc_module_name)
|
39
|
+
.map do |name, module_docs|
|
40
|
+
make_group(
|
41
|
+
module_docs,
|
42
|
+
name,
|
43
|
+
"The following declarations are provided by module #{name}.",
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
guide_categories + module_categories
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.group_custom_categories(docs, doc_index)
|
51
|
+
group = config.custom_categories.map do |category|
|
52
|
+
children = category['children'].map do |name|
|
53
|
+
unless doc = doc_index.lookup(name)
|
54
|
+
warn 'WARNING: No documented top-level declarations match ' \
|
55
|
+
"name \"#{name}\" specified in categories file"
|
56
|
+
next nil
|
57
|
+
end
|
58
|
+
|
59
|
+
unless doc.parent_in_code.nil?
|
60
|
+
warn "WARNING: Declaration \"#{doc.fully_qualified_module_name}\" " \
|
61
|
+
'specified in categories file exists but is not top-level and ' \
|
62
|
+
'cannot be included here'
|
63
|
+
next nil
|
64
|
+
end
|
65
|
+
|
66
|
+
docs.delete(doc)
|
67
|
+
end.compact
|
68
|
+
# Category config overrides alphabetization
|
69
|
+
children.each.with_index { |child, i| child.nav_order = i }
|
70
|
+
make_group(children, category['name'], '')
|
71
|
+
end
|
72
|
+
[group.compact, docs]
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.group_guides(docs, prefix)
|
76
|
+
guides, others = docs.partition { |doc| doc.type.markdown? }
|
77
|
+
return [[], others] unless guides.any?
|
78
|
+
|
79
|
+
[[make_type_group(guides, guides.first.type, prefix)], others]
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.make_type_group(docs, type, type_category_prefix)
|
83
|
+
make_group(
|
84
|
+
docs,
|
85
|
+
type_category_prefix + type.plural_name,
|
86
|
+
"The following #{type.plural_name.downcase} are available globally.",
|
87
|
+
type_category_prefix + type.plural_url_name,
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Join categories with the same name (eg. ObjC and Swift classes)
|
92
|
+
def self.merge_categories(categories)
|
93
|
+
merged = []
|
94
|
+
categories.each do |new_category|
|
95
|
+
if existing = merged.find { |cat| cat.name == new_category.name }
|
96
|
+
existing.children += new_category.children
|
97
|
+
else
|
98
|
+
merged.append(new_category)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
merged
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.make_group(group, name, abstract, url_name = nil)
|
105
|
+
group.reject! { |decl| decl.name.empty? }
|
106
|
+
unless group.empty?
|
107
|
+
SourceDeclaration.new.tap do |sd|
|
108
|
+
sd.type = SourceDeclaration::Type.overview
|
109
|
+
sd.name = name
|
110
|
+
sd.url_name = url_name
|
111
|
+
sd.abstract = Markdown.render(abstract)
|
112
|
+
sd.children = group
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Merge consecutive sections with the same mark into one section
|
118
|
+
# Needed because of pulling various decls into groups
|
119
|
+
def self.merge_consecutive_marks(docs)
|
120
|
+
prev_mark = nil
|
121
|
+
docs.each do |doc|
|
122
|
+
if prev_mark&.can_merge?(doc.mark)
|
123
|
+
doc.mark = prev_mark
|
124
|
+
end
|
125
|
+
prev_mark = doc.mark
|
126
|
+
merge_consecutive_marks(doc.children)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -52,7 +52,7 @@ module Jazzy
|
|
52
52
|
config.author_name = author_name(podspec)
|
53
53
|
config.author_name_configured = true
|
54
54
|
end
|
55
|
-
unless config.
|
55
|
+
unless config.module_name_known?
|
56
56
|
config.module_name = podspec.module_name
|
57
57
|
config.module_name_configured = true
|
58
58
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_support'
|
3
4
|
require 'active_support/inflector'
|
4
5
|
|
5
6
|
module Jazzy
|
@@ -163,8 +164,14 @@ module Jazzy
|
|
163
164
|
kind == 'sourcekitten.source.lang.objc.decl.unexposed'
|
164
165
|
end
|
165
166
|
|
167
|
+
OVERVIEW_KIND = 'Overview'
|
168
|
+
|
166
169
|
def self.overview
|
167
|
-
Type.new(
|
170
|
+
Type.new(OVERVIEW_KIND)
|
171
|
+
end
|
172
|
+
|
173
|
+
def overview?
|
174
|
+
kind == OVERVIEW_KIND
|
168
175
|
end
|
169
176
|
|
170
177
|
MARKDOWN_KIND = 'document.markdown'
|
@@ -193,7 +200,8 @@ module Jazzy
|
|
193
200
|
dash: 'Guide',
|
194
201
|
}.freeze,
|
195
202
|
|
196
|
-
|
203
|
+
# Group/Overview
|
204
|
+
OVERVIEW_KIND => {
|
197
205
|
jazzy: nil,
|
198
206
|
dash: 'Section',
|
199
207
|
}.freeze,
|
@@ -62,6 +62,7 @@ module Jazzy
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
+
# 'OuterType.NestedType.method(arg:)'
|
65
66
|
def fully_qualified_name
|
66
67
|
namespace_path.map(&:name).join('.')
|
67
68
|
end
|
@@ -74,6 +75,21 @@ module Jazzy
|
|
74
75
|
.join('(?:<.*?>)?\.'))
|
75
76
|
end
|
76
77
|
|
78
|
+
def fully_qualified_module_name_parts
|
79
|
+
path = namespace_path
|
80
|
+
path.map(&:name).prepend(path.first.module_name).compact
|
81
|
+
end
|
82
|
+
|
83
|
+
# 'MyModule.OuterType.NestedType.method(arg:)'
|
84
|
+
def fully_qualified_module_name
|
85
|
+
fully_qualified_module_name_parts.join('.')
|
86
|
+
end
|
87
|
+
|
88
|
+
# List of doc_parent decls, .last is self
|
89
|
+
def docs_path
|
90
|
+
(parent_in_docs&.docs_path || []) + [self]
|
91
|
+
end
|
92
|
+
|
77
93
|
# If this declaration is an objc category, returns an array with the name
|
78
94
|
# of the extended objc class and the category name itself, i.e.
|
79
95
|
# ["NSString", "MyMethods"], nil otherwise.
|
@@ -114,7 +130,7 @@ module Jazzy
|
|
114
130
|
attr_accessor :column
|
115
131
|
attr_accessor :usr
|
116
132
|
attr_accessor :type_usr
|
117
|
-
attr_accessor :
|
133
|
+
attr_accessor :module_name
|
118
134
|
attr_accessor :name
|
119
135
|
attr_accessor :objc_name
|
120
136
|
attr_accessor :declaration
|
@@ -140,6 +156,11 @@ module Jazzy
|
|
140
156
|
attr_accessor :inherited_types
|
141
157
|
attr_accessor :async
|
142
158
|
|
159
|
+
# The name of the module being documented that contains this
|
160
|
+
# declaration. Only different from module_name when this is
|
161
|
+
# an extension of a type from another module. Nil for guides.
|
162
|
+
attr_accessor :doc_module_name
|
163
|
+
|
143
164
|
def usage_discouraged?
|
144
165
|
unavailable || deprecated
|
145
166
|
end
|
@@ -183,20 +204,60 @@ module Jazzy
|
|
183
204
|
inherited_types.any? { |t| !unwanted.include?(t) }
|
184
205
|
end
|
185
206
|
|
186
|
-
# Pre-Swift 5.6: SourceKit only sets
|
187
|
-
# Swift 5.6+:
|
207
|
+
# Pre-Swift 5.6: SourceKit only sets module_name for imported modules
|
208
|
+
# Swift 5.6+: module_name is always set
|
188
209
|
def type_from_doc_module?
|
189
210
|
!type.extension? ||
|
190
211
|
(swift? && usr &&
|
191
|
-
(
|
212
|
+
(module_name.nil? || module_name == doc_module_name))
|
213
|
+
end
|
214
|
+
|
215
|
+
# Don't ask the user to write documentation for types being extended
|
216
|
+
# from other modules. Compile errors leave no docs and a `nil` USR.
|
217
|
+
def mark_undocumented?
|
218
|
+
!swift? || (usr && !extension_of_external_type?)
|
219
|
+
end
|
220
|
+
|
221
|
+
def extension_of_external_type?
|
222
|
+
!module_name.nil? &&
|
223
|
+
!Config.instance.module_name?(module_name)
|
224
|
+
end
|
225
|
+
|
226
|
+
# Is it unclear from context what module the (top-level) decl is from?
|
227
|
+
def ambiguous_module_name?(group_name)
|
228
|
+
extension_of_external_type? ||
|
229
|
+
(Config.instance.multiple_modules? &&
|
230
|
+
!module_name.nil? &&
|
231
|
+
group_name != module_name)
|
232
|
+
end
|
233
|
+
|
234
|
+
# Does the user need help understanding how to get this declaration?
|
235
|
+
def need_doc_module_note?
|
236
|
+
return false unless Config.instance.multiple_modules?
|
237
|
+
return false if docs_path.first.name == doc_module_name
|
238
|
+
|
239
|
+
if parent_in_code.nil?
|
240
|
+
# Top-level decls with no page of their own
|
241
|
+
!render_as_page?
|
242
|
+
else
|
243
|
+
# Members added by extension
|
244
|
+
parent_in_code.module_name != doc_module_name
|
245
|
+
end
|
192
246
|
end
|
193
247
|
|
194
248
|
# Info text for contents page by collapsed item name
|
195
249
|
def declaration_note
|
196
|
-
notes = [
|
197
|
-
|
198
|
-
|
199
|
-
|
250
|
+
notes = [
|
251
|
+
default_impl_abstract ? 'default implementation' : nil,
|
252
|
+
from_protocol_extension ? 'extension method' : nil,
|
253
|
+
async ? 'asynchronous' : nil,
|
254
|
+
need_doc_module_note? ? "from #{doc_module_name}" : nil,
|
255
|
+
].compact
|
256
|
+
notes.join(', ').upcase_first unless notes.empty?
|
257
|
+
end
|
258
|
+
|
259
|
+
def readme?
|
260
|
+
false
|
200
261
|
end
|
201
262
|
|
202
263
|
def alternative_abstract
|
@@ -27,6 +27,10 @@ module Jazzy
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
def readme?
|
31
|
+
url == 'index.html'
|
32
|
+
end
|
33
|
+
|
30
34
|
def render_as_page?
|
31
35
|
true
|
32
36
|
end
|
@@ -89,7 +93,7 @@ pod '#{podspec.name}'
|
|
89
93
|
README
|
90
94
|
else
|
91
95
|
<<-README
|
92
|
-
# #{source_module.
|
96
|
+
# #{source_module.readme_title}
|
93
97
|
|
94
98
|
### Authors
|
95
99
|
|
data/lib/jazzy/source_module.rb
CHANGED
@@ -7,28 +7,30 @@ require 'jazzy/source_declaration'
|
|
7
7
|
require 'jazzy/source_host'
|
8
8
|
|
9
9
|
module Jazzy
|
10
|
+
# A cache of info that is common across all page templating, gathered
|
11
|
+
# from other parts of the program.
|
10
12
|
class SourceModule
|
11
|
-
|
13
|
+
include Config::Mixin
|
14
|
+
|
15
|
+
attr_accessor :readme_title
|
12
16
|
attr_accessor :docs
|
13
17
|
attr_accessor :doc_coverage
|
14
18
|
attr_accessor :doc_structure
|
15
19
|
attr_accessor :author_name
|
16
20
|
attr_accessor :author_url
|
17
|
-
attr_accessor :
|
21
|
+
attr_accessor :dash_feed_url
|
18
22
|
attr_accessor :host
|
19
23
|
|
20
|
-
def initialize(
|
24
|
+
def initialize(docs, doc_structure, doc_coverage, docset_builder)
|
21
25
|
self.docs = docs
|
22
26
|
self.doc_structure = doc_structure
|
23
27
|
self.doc_coverage = doc_coverage
|
24
|
-
|
25
|
-
self.
|
26
|
-
self.
|
27
|
-
self.
|
28
|
-
|
29
|
-
|
30
|
-
self.dash_url =
|
31
|
-
"dash-feed://#{ERB::Util.url_encode(options.dash_url.to_s)}"
|
28
|
+
title = config.readme_title || config.module_names.first
|
29
|
+
self.readme_title = title.empty? ? 'Index' : title
|
30
|
+
self.author_name = config.author_name
|
31
|
+
self.author_url = config.author_url
|
32
|
+
self.host = SourceHost.create(config)
|
33
|
+
self.dash_feed_url = docset_builder.dash_feed_url
|
32
34
|
end
|
33
35
|
|
34
36
|
def all_declarations
|