jazzy 0.14.4 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/Tests.yml +6 -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/sourcekitten.rb
CHANGED
@@ -13,6 +13,8 @@ require 'jazzy/highlighter'
|
|
13
13
|
require 'jazzy/source_declaration'
|
14
14
|
require 'jazzy/source_mark'
|
15
15
|
require 'jazzy/stats'
|
16
|
+
require 'jazzy/grouper'
|
17
|
+
require 'jazzy/doc_index'
|
16
18
|
|
17
19
|
ELIDED_AUTOLINK_TOKEN = '36f8f5912051ae747ef441d6511ca4cb'
|
18
20
|
|
@@ -60,83 +62,9 @@ module Jazzy
|
|
60
62
|
).freeze
|
61
63
|
end
|
62
64
|
|
63
|
-
#
|
64
|
-
|
65
|
-
|
66
|
-
unlisted_prefix = Config.instance.custom_categories_unlisted_prefix
|
67
|
-
type_categories, uncategorized = group_type_categories(
|
68
|
-
docs, custom_categories.any? ? unlisted_prefix : ''
|
69
|
-
)
|
70
|
-
custom_categories + merge_categories(type_categories) + uncategorized
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.group_custom_categories(docs)
|
74
|
-
group = Config.instance.custom_categories.map do |category|
|
75
|
-
children = category['children'].flat_map do |name|
|
76
|
-
docs_with_name, docs = docs.partition { |doc| doc.name == name }
|
77
|
-
if docs_with_name.empty?
|
78
|
-
warn 'WARNING: No documented top-level declarations match ' \
|
79
|
-
"name \"#{name}\" specified in categories file"
|
80
|
-
end
|
81
|
-
docs_with_name
|
82
|
-
end
|
83
|
-
# Category config overrides alphabetization
|
84
|
-
children.each.with_index { |child, i| child.nav_order = i }
|
85
|
-
make_group(children, category['name'], '')
|
86
|
-
end
|
87
|
-
[group.compact, docs]
|
88
|
-
end
|
89
|
-
|
90
|
-
def self.group_type_categories(docs, type_category_prefix)
|
91
|
-
group = SourceDeclaration::Type.all.map do |type|
|
92
|
-
children, docs = docs.partition { |doc| doc.type == type }
|
93
|
-
make_group(
|
94
|
-
children,
|
95
|
-
type_category_prefix + type.plural_name,
|
96
|
-
"The following #{type.plural_name.downcase} are available globally.",
|
97
|
-
type_category_prefix + type.plural_url_name,
|
98
|
-
)
|
99
|
-
end
|
100
|
-
[group.compact, docs]
|
101
|
-
end
|
102
|
-
|
103
|
-
# Join categories with the same name (eg. ObjC and Swift classes)
|
104
|
-
def self.merge_categories(categories)
|
105
|
-
merged = []
|
106
|
-
categories.each do |new_category|
|
107
|
-
if existing = merged.find { |c| c.name == new_category.name }
|
108
|
-
existing.children += new_category.children
|
109
|
-
else
|
110
|
-
merged.append(new_category)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
merged
|
114
|
-
end
|
115
|
-
|
116
|
-
def self.make_group(group, name, abstract, url_name = nil)
|
117
|
-
group.reject! { |doc| doc.name.empty? }
|
118
|
-
unless group.empty?
|
119
|
-
SourceDeclaration.new.tap do |sd|
|
120
|
-
sd.type = SourceDeclaration::Type.overview
|
121
|
-
sd.name = name
|
122
|
-
sd.url_name = url_name
|
123
|
-
sd.abstract = Markdown.render(abstract)
|
124
|
-
sd.children = group
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
# Merge consecutive sections with the same mark into one section
|
130
|
-
def self.merge_consecutive_marks(docs)
|
131
|
-
prev_mark = nil
|
132
|
-
docs.each do |doc|
|
133
|
-
if prev_mark&.can_merge?(doc.mark)
|
134
|
-
doc.mark = prev_mark
|
135
|
-
end
|
136
|
-
prev_mark = doc.mark
|
137
|
-
merge_consecutive_marks(doc.children)
|
138
|
-
end
|
139
|
-
end
|
65
|
+
#
|
66
|
+
# URL assignment
|
67
|
+
#
|
140
68
|
|
141
69
|
def self.sanitize_filename(doc)
|
142
70
|
unsafe_filename = doc.docs_filename
|
@@ -149,7 +77,7 @@ module Jazzy
|
|
149
77
|
end
|
150
78
|
|
151
79
|
# rubocop:disable Metrics/MethodLength
|
152
|
-
# Generate doc URL by prepending its parents URLs
|
80
|
+
# Generate doc URL by prepending its parents' URLs
|
153
81
|
# @return [Hash] input docs with URLs
|
154
82
|
def self.make_doc_urls(docs)
|
155
83
|
docs.each do |doc|
|
@@ -189,18 +117,50 @@ module Jazzy
|
|
189
117
|
# Guides in the root for back-compatibility.
|
190
118
|
# Declarations under outer namespace type (Structures, Classes, etc.)
|
191
119
|
def self.subdir_for_doc(doc)
|
192
|
-
|
193
|
-
|
194
|
-
top_level_decl = doc.namespace_path.first
|
195
|
-
if top_level_decl.type.name
|
196
|
-
[top_level_decl.type.plural_url_name] +
|
197
|
-
doc.namespace_ancestors.map(&:name)
|
120
|
+
if Config.instance.multiple_modules?
|
121
|
+
subdir_for_doc_multi_module(doc)
|
198
122
|
else
|
199
|
-
#
|
200
|
-
|
123
|
+
# Back-compatibility layout version
|
124
|
+
subdir_for_doc_single_module(doc)
|
201
125
|
end
|
202
126
|
end
|
203
127
|
|
128
|
+
# Pre-multi-module site layout, does not allow for
|
129
|
+
# types with the same name.
|
130
|
+
def self.subdir_for_doc_single_module(doc)
|
131
|
+
# Guides + Groups in the root
|
132
|
+
return [] if doc.type.markdown? || doc.type.overview?
|
133
|
+
|
134
|
+
[doc.namespace_path.first.type.plural_url_name] +
|
135
|
+
doc.namespace_ancestors.map(&:name)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Multi-module site layout, separate each module that
|
139
|
+
# is being documented.
|
140
|
+
def self.subdir_for_doc_multi_module(doc)
|
141
|
+
# Guides + Groups in the root
|
142
|
+
return [] if doc.type.markdown? || doc.type.overview?
|
143
|
+
|
144
|
+
root_decl = doc.namespace_path.first
|
145
|
+
|
146
|
+
# Extensions need an extra dir to allow for extending
|
147
|
+
# ExternalModule1.TypeName and ExternalModule2.TypeName
|
148
|
+
namespace_subdir =
|
149
|
+
if root_decl.type.swift_extension?
|
150
|
+
['Extensions', root_decl.module_name]
|
151
|
+
else
|
152
|
+
[doc.namespace_path.first.type.plural_url_name]
|
153
|
+
end
|
154
|
+
|
155
|
+
[root_decl.doc_module_name] +
|
156
|
+
namespace_subdir +
|
157
|
+
doc.namespace_ancestors.map(&:name)
|
158
|
+
end
|
159
|
+
|
160
|
+
#
|
161
|
+
# CLI argument calculation
|
162
|
+
#
|
163
|
+
|
204
164
|
# returns all subdirectories of specified path
|
205
165
|
def self.rec_path(path)
|
206
166
|
path.children.collect do |child|
|
@@ -210,42 +170,42 @@ module Jazzy
|
|
210
170
|
end.select { |x| x }.flatten(1)
|
211
171
|
end
|
212
172
|
|
213
|
-
def self.use_spm?(
|
214
|
-
|
215
|
-
(!
|
173
|
+
def self.use_spm?(module_config)
|
174
|
+
module_config.swift_build_tool == :spm ||
|
175
|
+
(!module_config.swift_build_tool_configured &&
|
216
176
|
Dir['*.xcodeproj', '*.xcworkspace'].empty? &&
|
217
|
-
!
|
218
|
-
!
|
177
|
+
!module_config.build_tool_arguments.include?('-project') &&
|
178
|
+
!module_config.build_tool_arguments.include?('-workspace'))
|
219
179
|
end
|
220
180
|
|
221
181
|
# Builds SourceKitten arguments based on Jazzy options
|
222
|
-
def self.arguments_from_options(
|
182
|
+
def self.arguments_from_options(module_config)
|
223
183
|
arguments = ['doc']
|
224
|
-
if
|
225
|
-
arguments += objc_arguments_from_options(
|
184
|
+
if module_config.objc_mode
|
185
|
+
arguments += objc_arguments_from_options(module_config)
|
226
186
|
else
|
227
|
-
arguments += ['--spm'] if use_spm?(
|
228
|
-
unless
|
229
|
-
arguments += ['--module-name',
|
187
|
+
arguments += ['--spm'] if use_spm?(module_config)
|
188
|
+
unless module_config.module_name.empty?
|
189
|
+
arguments += ['--module-name', module_config.module_name]
|
230
190
|
end
|
231
191
|
arguments += ['--']
|
232
192
|
end
|
233
193
|
|
234
|
-
arguments +
|
194
|
+
arguments + module_config.build_tool_arguments
|
235
195
|
end
|
236
196
|
|
237
|
-
def self.objc_arguments_from_options(
|
197
|
+
def self.objc_arguments_from_options(module_config)
|
238
198
|
arguments = []
|
239
|
-
if
|
240
|
-
arguments += ['--objc',
|
199
|
+
if module_config.build_tool_arguments.empty?
|
200
|
+
arguments += ['--objc', module_config.umbrella_header.to_s, '--', '-x',
|
241
201
|
'objective-c', '-isysroot',
|
242
|
-
`xcrun --show-sdk-path --sdk #{
|
243
|
-
'-I',
|
202
|
+
`xcrun --show-sdk-path --sdk #{module_config.sdk}`.chomp,
|
203
|
+
'-I', module_config.framework_root.to_s,
|
244
204
|
'-fmodules']
|
245
205
|
end
|
246
206
|
# add additional -I arguments for each subdirectory of framework_root
|
247
|
-
unless
|
248
|
-
rec_path(Pathname.new(
|
207
|
+
unless module_config.framework_root.nil?
|
208
|
+
rec_path(Pathname.new(module_config.framework_root.to_s)).collect do |child|
|
249
209
|
if child.directory?
|
250
210
|
arguments += ['-I', child.to_s]
|
251
211
|
end
|
@@ -270,6 +230,10 @@ module Jazzy
|
|
270
230
|
output
|
271
231
|
end
|
272
232
|
|
233
|
+
#
|
234
|
+
# SourceDeclaration generation
|
235
|
+
#
|
236
|
+
|
273
237
|
def self.make_default_doc_info(declaration)
|
274
238
|
# @todo: Fix these
|
275
239
|
declaration.abstract = ''
|
@@ -352,18 +316,10 @@ module Jazzy
|
|
352
316
|
end
|
353
317
|
end
|
354
318
|
|
355
|
-
# Call things undocumented if they were compiled properly
|
356
|
-
# and came from our module.
|
357
|
-
def self.should_mark_undocumented(declaration)
|
358
|
-
declaration.usr &&
|
359
|
-
(declaration.modulename.nil? ||
|
360
|
-
declaration.modulename == Config.instance.module_name)
|
361
|
-
end
|
362
|
-
|
363
319
|
def self.process_undocumented_token(doc, declaration)
|
364
320
|
make_default_doc_info(declaration)
|
365
321
|
|
366
|
-
if
|
322
|
+
if declaration.mark_undocumented?
|
367
323
|
@stats.add_undocumented(declaration)
|
368
324
|
return nil if @skip_undocumented
|
369
325
|
|
@@ -621,7 +577,15 @@ module Jazzy
|
|
621
577
|
declaration.file = Pathname(doc['key.filepath']) if doc['key.filepath']
|
622
578
|
declaration.usr = doc['key.usr']
|
623
579
|
declaration.type_usr = doc['key.typeusr']
|
624
|
-
declaration.
|
580
|
+
declaration.module_name =
|
581
|
+
if declaration.swift?
|
582
|
+
# Filter out Apple sub-framework implementation names
|
583
|
+
doc['key.modulename']&.sub(/\..*$/, '')
|
584
|
+
else
|
585
|
+
# ObjC best effort, category original module is unavailable
|
586
|
+
@current_module_name
|
587
|
+
end
|
588
|
+
declaration.doc_module_name = @current_module_name
|
625
589
|
declaration.name = documented_name
|
626
590
|
declaration.mark = current_mark
|
627
591
|
declaration.access_control_level =
|
@@ -665,6 +629,10 @@ module Jazzy
|
|
665
629
|
Regexp.last_match[1].gsub(/\s+/, ' ')
|
666
630
|
end
|
667
631
|
|
632
|
+
#
|
633
|
+
# SourceDeclaration generation - extension management
|
634
|
+
#
|
635
|
+
|
668
636
|
# Expands extensions of nested types declared at the top level into
|
669
637
|
# a tree so they can be deduplicated properly
|
670
638
|
def self.expand_extensions(decls)
|
@@ -689,7 +657,8 @@ module Jazzy
|
|
689
657
|
SourceDeclaration.new.tap do |decl|
|
690
658
|
make_default_doc_info(decl)
|
691
659
|
decl.name = name
|
692
|
-
decl.
|
660
|
+
decl.module_name = extension.module_name
|
661
|
+
decl.doc_module_name = extension.doc_module_name
|
693
662
|
decl.type = extension.type
|
694
663
|
decl.mark = extension.mark
|
695
664
|
decl.usr = candidates.first.usr unless candidates.empty?
|
@@ -720,9 +689,10 @@ module Jazzy
|
|
720
689
|
|
721
690
|
# Returns true if an Objective-C declaration is mergeable.
|
722
691
|
def self.mergeable_objc?(decl, root_decls)
|
723
|
-
decl.type.objc_class?
|
724
|
-
|
725
|
-
|
692
|
+
decl.type.objc_class? ||
|
693
|
+
(decl.type.objc_category? &&
|
694
|
+
(category_classname = decl.objc_category_name[0]) &&
|
695
|
+
root_decls.any? { |d| d.name == category_classname })
|
726
696
|
end
|
727
697
|
|
728
698
|
# Returns if a Swift declaration is mergeable.
|
@@ -733,22 +703,45 @@ module Jazzy
|
|
733
703
|
decl.type.swift_typealias?
|
734
704
|
end
|
735
705
|
|
706
|
+
# Normally merge all extensions into their types and each other.
|
707
|
+
#
|
708
|
+
# :none means only merge within a module -- so two extensions to
|
709
|
+
# some type get merged, but an extension to a type from
|
710
|
+
# another documented module does not get merged into that type
|
711
|
+
# :extensions means extensions of documented modules get merged,
|
712
|
+
# but if we're documenting ModA and ModB, and they both provide
|
713
|
+
# extensions to Swift.String, then those two extensions still
|
714
|
+
# appear separately.
|
715
|
+
#
|
716
|
+
# (The USR part of the dedup key means ModA.Foo and ModB.Foo do not
|
717
|
+
# get merged.)
|
718
|
+
def self.module_deduplication_key(decl)
|
719
|
+
if (Config.instance.merge_modules == :none) ||
|
720
|
+
(Config.instance.merge_modules == :extensions &&
|
721
|
+
decl.extension_of_external_type?)
|
722
|
+
decl.doc_module_name
|
723
|
+
else
|
724
|
+
''
|
725
|
+
end
|
726
|
+
end
|
727
|
+
|
736
728
|
# Two declarations get merged if they have the same deduplication key.
|
737
729
|
def self.deduplication_key(decl, root_decls)
|
730
|
+
mod_key = module_deduplication_key(decl)
|
738
731
|
# Swift extension of objc class
|
739
732
|
if decl.swift_objc_extension?
|
740
|
-
[decl.swift_extension_objc_name, :objc_class_and_categories]
|
733
|
+
[decl.swift_extension_objc_name, :objc_class_and_categories, mod_key]
|
741
734
|
# Swift type or Swift extension of Swift type
|
742
735
|
elsif mergeable_swift?(decl)
|
743
|
-
[decl.usr, decl.name]
|
736
|
+
[decl.usr, decl.name, mod_key]
|
744
737
|
# Objc categories and classes
|
745
738
|
elsif mergeable_objc?(decl, root_decls)
|
746
739
|
# Using the ObjC name to match swift_objc_extension.
|
747
740
|
name, _ = decl.objc_category_name || decl.objc_name
|
748
|
-
[name, :objc_class_and_categories]
|
741
|
+
[name, :objc_class_and_categories, mod_key]
|
749
742
|
# Non-mergable declarations (funcs, typedefs etc...)
|
750
743
|
else
|
751
|
-
[decl.usr, decl.name, decl.type.kind]
|
744
|
+
[decl.usr, decl.name, decl.type.kind, '']
|
752
745
|
end
|
753
746
|
end
|
754
747
|
|
@@ -904,81 +897,47 @@ module Jazzy
|
|
904
897
|
# declaration: public protocol conformances and, for top-level extensions,
|
905
898
|
# further conditional extensions of the same type.
|
906
899
|
def self.merge_code_declaration(decls)
|
907
|
-
first = decls.first
|
908
|
-
|
909
900
|
declarations = decls[1..].select do |decl|
|
910
901
|
decl.type.swift_extension? &&
|
911
902
|
(decl.other_inherited_types?(@inaccessible_protocols) ||
|
912
|
-
(first.type.swift_extension? && decl.constrained_extension?))
|
913
|
-
end.
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
def self.filter_files(json)
|
922
|
-
json = filter_included_files(json) if Config.instance.included_files.any?
|
923
|
-
json = filter_excluded_files(json) if Config.instance.excluded_files.any?
|
924
|
-
json.map do |doc|
|
925
|
-
key = doc.keys.first
|
926
|
-
doc[key]
|
927
|
-
end.compact
|
928
|
-
end
|
929
|
-
|
930
|
-
# Filter based on the "included" flag.
|
931
|
-
def self.filter_included_files(json)
|
932
|
-
included_files = Config.instance.included_files
|
933
|
-
json.map do |doc|
|
934
|
-
key = doc.keys.first
|
935
|
-
doc if included_files.detect do |include|
|
936
|
-
File.fnmatch?(include, key)
|
903
|
+
(decls.first.type.swift_extension? && decl.constrained_extension?))
|
904
|
+
end.prepend(decls.first)
|
905
|
+
|
906
|
+
html_declaration = ''
|
907
|
+
until declarations.empty?
|
908
|
+
module_decls, declarations = next_doc_module_group(declarations)
|
909
|
+
first = module_decls.first
|
910
|
+
if need_doc_module_note?(first, html_declaration)
|
911
|
+
html_declaration += "<span class='declaration-note'>From #{first.doc_module_name}:</span>"
|
937
912
|
end
|
938
|
-
|
939
|
-
|
913
|
+
html_declaration += module_decls.map(&:declaration).uniq.join
|
914
|
+
end
|
940
915
|
|
941
|
-
|
942
|
-
|
943
|
-
excluded_files = Config.instance.excluded_files
|
944
|
-
json.map do |doc|
|
945
|
-
key = doc.keys.first
|
946
|
-
doc unless excluded_files.detect do |exclude|
|
947
|
-
File.fnmatch?(exclude, key)
|
948
|
-
end
|
949
|
-
end.compact
|
916
|
+
# Must preserve `nil` for edge cases
|
917
|
+
decls.first.declaration = html_declaration unless html_declaration.empty?
|
950
918
|
end
|
951
919
|
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
.gsub('\.\.\.', '[^)]*')
|
957
|
-
.gsub(/<.*>/, '')
|
958
|
-
|
959
|
-
whole_name_pat = /\A#{wildcard_expansion}\Z/
|
960
|
-
docs.find do |doc|
|
961
|
-
whole_name_pat =~ doc.name
|
920
|
+
# Grab all the extensions from the same doc module
|
921
|
+
def self.next_doc_module_group(decls)
|
922
|
+
decls.partition do |decl|
|
923
|
+
decl.doc_module_name == decls.first.doc_module_name
|
962
924
|
end
|
963
925
|
end
|
964
926
|
|
965
|
-
#
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
927
|
+
# Does this extension/type need a note explaining which doc module it is from?
|
928
|
+
# Only for extensions, if there actually are multiple modules.
|
929
|
+
# Last condition avoids it for simple 'extension Array'.
|
930
|
+
def self.need_doc_module_note?(decl, html_declaration)
|
931
|
+
Config.instance.multiple_modules? &&
|
932
|
+
decl.type.swift_extension? &&
|
933
|
+
!(html_declaration.empty? &&
|
934
|
+
!decl.constrained_extension? &&
|
935
|
+
!decl.inherited_types?)
|
973
936
|
end
|
974
937
|
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
doc = name_match(next_part, doc.children)
|
979
|
-
end
|
980
|
-
doc
|
981
|
-
end
|
938
|
+
#
|
939
|
+
# Autolinking
|
940
|
+
#
|
982
941
|
|
983
942
|
# Links recognized top-level declarations within
|
984
943
|
# - inlined code within docs
|
@@ -987,85 +946,97 @@ module Jazzy
|
|
987
946
|
# The `after_highlight` flag is used to differentiate between the two modes.
|
988
947
|
#
|
989
948
|
# DocC link format - follow Xcode and don't display slash-separated parts.
|
990
|
-
|
991
|
-
def self.autolink_text(text, doc, root_decls, after_highlight: false)
|
949
|
+
def self.autolink_text(text, doc, after_highlight: false)
|
992
950
|
text.autolink_block(doc.url, '[^\s]+', after_highlight) do |raw_name|
|
993
951
|
sym_name =
|
994
952
|
(raw_name[/^<doc:(.*)>$/, 1] || raw_name).sub(/(?<!^)-.+$/, '')
|
995
953
|
|
996
|
-
|
997
|
-
.sub(/^@/, '') # ignore for custom attribute ref
|
998
|
-
.split(%r{(?<!\.)[/.](?!\.)}) # dot or slash, but not '...'
|
999
|
-
.reject(&:empty?)
|
1000
|
-
|
1001
|
-
# First dot-separated component can match any ancestor or top-level doc
|
1002
|
-
first_part = parts.shift
|
1003
|
-
name_root = ancestor_name_match(first_part, doc) ||
|
1004
|
-
name_match(first_part, root_decls)
|
1005
|
-
|
1006
|
-
# Traverse children via subsequent components, if any
|
1007
|
-
[name_traversal(parts, name_root), sym_name.sub(%r{^.*/}, '')]
|
954
|
+
[@doc_index.lookup(sym_name, doc), sym_name.sub(%r{^.*/}, '')]
|
1008
955
|
end.autolink_block(doc.url, '[+-]\[\w+(?: ?\(\w+\))? [\w:]+\]',
|
1009
956
|
after_highlight) do |raw_name|
|
1010
|
-
|
1011
|
-
|
1012
|
-
# Subject component can match any ancestor or top-level doc
|
1013
|
-
subject = match[2].delete(' ')
|
1014
|
-
name_root = ancestor_name_match(subject, doc) ||
|
1015
|
-
name_match(subject, root_decls)
|
1016
|
-
|
1017
|
-
if name_root
|
1018
|
-
# Look up the verb in the subject’s children
|
1019
|
-
[name_match(match[1] + match[3], name_root.children), raw_name]
|
1020
|
-
end
|
957
|
+
[@doc_index.lookup(raw_name, doc), raw_name]
|
1021
958
|
end.autolink_block(doc.url, '[+-]\w[\w:]*', after_highlight) do |raw_name|
|
1022
|
-
[
|
959
|
+
[@doc_index.lookup(raw_name, doc), raw_name]
|
1023
960
|
end
|
1024
961
|
end
|
1025
|
-
# rubocop:enable Metrics/MethodLength
|
1026
962
|
|
1027
963
|
AUTOLINK_TEXT_FIELDS = %w[return
|
1028
964
|
abstract
|
1029
965
|
unavailable_message
|
1030
966
|
deprecation_message].freeze
|
1031
967
|
|
1032
|
-
def self.autolink_text_fields(doc
|
968
|
+
def self.autolink_text_fields(doc)
|
1033
969
|
AUTOLINK_TEXT_FIELDS.each do |field|
|
1034
970
|
if text = doc.send(field)
|
1035
|
-
doc.send(field + '=', autolink_text(text, doc
|
971
|
+
doc.send(field + '=', autolink_text(text, doc))
|
1036
972
|
end
|
1037
973
|
end
|
1038
974
|
|
1039
975
|
(doc.parameters || []).each do |param|
|
1040
976
|
param[:discussion] =
|
1041
|
-
autolink_text(param[:discussion], doc
|
977
|
+
autolink_text(param[:discussion], doc)
|
1042
978
|
end
|
1043
979
|
end
|
1044
980
|
|
1045
981
|
AUTOLINK_HIGHLIGHT_FIELDS = %w[declaration
|
1046
982
|
other_language_declaration].freeze
|
1047
983
|
|
1048
|
-
def self.autolink_highlight_fields(doc
|
984
|
+
def self.autolink_highlight_fields(doc)
|
1049
985
|
AUTOLINK_HIGHLIGHT_FIELDS.each do |field|
|
1050
986
|
if text = doc.send(field)
|
1051
987
|
doc.send(field + '=',
|
1052
|
-
autolink_text(text, doc,
|
988
|
+
autolink_text(text, doc, after_highlight: true))
|
1053
989
|
end
|
1054
990
|
end
|
1055
991
|
end
|
1056
992
|
|
1057
|
-
def self.autolink(docs
|
1058
|
-
@autolink_root_decls = root_decls
|
993
|
+
def self.autolink(docs)
|
1059
994
|
docs.each do |doc|
|
1060
|
-
doc.children = autolink(doc.children
|
1061
|
-
autolink_text_fields(doc
|
1062
|
-
autolink_highlight_fields(doc
|
995
|
+
doc.children = autolink(doc.children)
|
996
|
+
autolink_text_fields(doc)
|
997
|
+
autolink_highlight_fields(doc)
|
1063
998
|
end
|
1064
999
|
end
|
1065
1000
|
|
1066
1001
|
# For autolinking external markdown documents
|
1067
1002
|
def self.autolink_document(html, doc)
|
1068
|
-
autolink_text(html, doc
|
1003
|
+
autolink_text(html, doc)
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
#
|
1007
|
+
# Entrypoint and misc filtering
|
1008
|
+
#
|
1009
|
+
|
1010
|
+
# Apply filtering based on the "included" and "excluded" flags.
|
1011
|
+
def self.filter_files(json)
|
1012
|
+
json = filter_included_files(json) if Config.instance.included_files.any?
|
1013
|
+
json = filter_excluded_files(json) if Config.instance.excluded_files.any?
|
1014
|
+
json.map do |doc|
|
1015
|
+
key = doc.keys.first
|
1016
|
+
doc[key]
|
1017
|
+
end.compact
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
# Filter based on the "included" flag.
|
1021
|
+
def self.filter_included_files(json)
|
1022
|
+
included_files = Config.instance.included_files
|
1023
|
+
json.map do |doc|
|
1024
|
+
key = doc.keys.first
|
1025
|
+
doc if included_files.detect do |include|
|
1026
|
+
File.fnmatch?(include, key)
|
1027
|
+
end
|
1028
|
+
end.compact
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
# Filter based on the "excluded" flag.
|
1032
|
+
def self.filter_excluded_files(json)
|
1033
|
+
excluded_files = Config.instance.excluded_files
|
1034
|
+
json.map do |doc|
|
1035
|
+
key = doc.keys.first
|
1036
|
+
doc unless excluded_files.detect do |exclude|
|
1037
|
+
File.fnmatch?(exclude, key)
|
1038
|
+
end
|
1039
|
+
end.compact
|
1069
1040
|
end
|
1070
1041
|
|
1071
1042
|
def self.reject_objc_types(docs)
|
@@ -1083,26 +1054,51 @@ module Jazzy
|
|
1083
1054
|
end
|
1084
1055
|
end
|
1085
1056
|
|
1057
|
+
# Remove top-level enum cases because it means they have an ACL lower
|
1058
|
+
# than min_acl
|
1059
|
+
def self.reject_swift_types(docs)
|
1060
|
+
docs.reject { |doc| doc.type.swift_enum_element? }
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
# Spot and mark any categories on classes not declared in these docs
|
1064
|
+
def self.mark_objc_external_categories(docs)
|
1065
|
+
class_names = docs.select { |doc| doc.type.objc_class? }.to_set(&:name)
|
1066
|
+
|
1067
|
+
docs.map do |doc|
|
1068
|
+
if (names = doc.objc_category_name) && !class_names.include?(names.first)
|
1069
|
+
doc.module_name = '(Imported)'
|
1070
|
+
end
|
1071
|
+
doc
|
1072
|
+
end
|
1073
|
+
end
|
1074
|
+
|
1086
1075
|
# Parse sourcekitten STDOUT output as JSON
|
1087
1076
|
# @return [Hash] structured docs
|
1088
|
-
def self.parse(sourcekitten_output,
|
1089
|
-
@min_acl = min_acl
|
1090
|
-
@skip_undocumented = skip_undocumented
|
1077
|
+
def self.parse(sourcekitten_output, options, inject_docs)
|
1078
|
+
@min_acl = options.min_acl
|
1079
|
+
@skip_undocumented = options.skip_undocumented
|
1091
1080
|
@stats = Stats.new
|
1092
1081
|
@inaccessible_protocols = []
|
1093
|
-
|
1094
|
-
|
1082
|
+
|
1083
|
+
# Process each module separately to inject the source module name
|
1084
|
+
docs = sourcekitten_output.zip(options.module_names).map do |json, name|
|
1085
|
+
@current_module_name = name
|
1086
|
+
sourcekitten_dicts = filter_files(JSON.parse(json).flatten)
|
1087
|
+
make_source_declarations(sourcekitten_dicts)
|
1088
|
+
end.flatten + inject_docs
|
1089
|
+
|
1095
1090
|
docs = expand_extensions(docs)
|
1096
1091
|
docs = deduplicate_declarations(docs)
|
1097
1092
|
docs = reject_objc_types(docs)
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1093
|
+
docs = reject_swift_types(docs)
|
1094
|
+
docs = mark_objc_external_categories(docs)
|
1095
|
+
|
1096
|
+
@doc_index = DocIndex.new(docs)
|
1097
|
+
|
1098
|
+
docs = Grouper.group_docs(docs, @doc_index)
|
1099
|
+
|
1104
1100
|
make_doc_urls(docs)
|
1105
|
-
autolink(docs
|
1101
|
+
autolink(docs)
|
1106
1102
|
[docs, @stats]
|
1107
1103
|
end
|
1108
1104
|
end
|