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/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
|