diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ea2c7461..26dc30459 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ ##### Breaking -* None. +* Report number of included and skipped declarations in CLI output. + [John Fairhurst](https://github.com/johnfairh) + [#238](https://github.com/realm/jazzy/issues/238) ##### Enhancements diff --git a/lib/jazzy/config.rb b/lib/jazzy/config.rb index b2b79357a..0f4cd1d06 100644 --- a/lib/jazzy/config.rb +++ b/lib/jazzy/config.rb @@ -259,7 +259,8 @@ def expand_path(path) default: false config_attr :min_acl, - command_line: '--min-acl [private | internal | public]', + command_line: + '--min-acl [private | fileprivate | internal | public | open]', description: 'minimum access control level to document', default: 'public', parse: ->(acl) do diff --git a/lib/jazzy/doc_builder.rb b/lib/jazzy/doc_builder.rb index dcad57119..d78a4dc7c 100644 --- a/lib/jazzy/doc_builder.rb +++ b/lib/jazzy/doc_builder.rb @@ -143,7 +143,7 @@ def self.build_site(docs, coverage, options) # @param [Config] options Build options # @return [SourceModule] the documented source module def self.build_docs_for_sourcekitten_output(sourcekitten_output, options) - (docs, coverage, undocumented) = SourceKitten.parse( + (docs, stats) = SourceKitten.parse( sourcekitten_output, options.min_acl, options.skip_undocumented, @@ -152,15 +152,13 @@ def self.build_docs_for_sourcekitten_output(sourcekitten_output, options) prepare_output_dir(options.output, options.clean) - puts "#{coverage}\% documentation coverage " \ - "with #{undocumented.count} undocumented symbol" \ - "#{undocumented.count == 1 ? '' : 's'}" + stats.report unless options.skip_documentation - build_site(docs, coverage, options) + build_site(docs, stats.doc_coverage, options) end - write_lint_report(undocumented, options) + write_lint_report(stats.undocumented_decls, options) end def self.relative_path_if_inside(path, base_path) diff --git a/lib/jazzy/source_declaration/access_control_level.rb b/lib/jazzy/source_declaration/access_control_level.rb index ef831e493..a55722ff2 100644 --- a/lib/jazzy/source_declaration/access_control_level.rb +++ b/lib/jazzy/source_declaration/access_control_level.rb @@ -89,6 +89,14 @@ def self.open def <=>(other) LEVELS[level] <=> LEVELS[other.level] end + + def included_levels + LEVELS.select { |_, v| v >= LEVELS[level] }.keys + end + + def excluded_levels + LEVELS.select { |_, v| v < LEVELS[level] }.keys + end end end end diff --git a/lib/jazzy/sourcekitten.rb b/lib/jazzy/sourcekitten.rb index bb1d0ccd1..a606789f8 100644 --- a/lib/jazzy/sourcekitten.rb +++ b/lib/jazzy/sourcekitten.rb @@ -8,6 +8,7 @@ require 'jazzy/highlighter' require 'jazzy/source_declaration' require 'jazzy/source_mark' +require 'jazzy/stats' ELIDED_AUTOLINK_TOKEN = '36f8f5912051ae747ef441d6511ca4cb'.freeze @@ -46,8 +47,6 @@ def autolink_block(doc_url, middle_regex, after_highlight) module Jazzy # This module interacts with the sourcekitten command-line executable module SourceKitten - @documented_count = 0 - @undocumented_decls = [] @default_abstract = Markdown.render('Undocumented').freeze # Group root-level docs by custom categories (if any) and type @@ -264,7 +263,8 @@ def self.should_document?(doc) end end - SourceDeclaration::AccessControlLevel.from_doc(doc) >= @min_acl + acl_ok = SourceDeclaration::AccessControlLevel.from_doc(doc) >= @min_acl + acl_ok.tap { @stats.add_acl_skipped unless acl_ok } end # rubocop:enable Metrics/CyclomaticComplexity # rubocop:enable Metrics/PerceivedComplexity @@ -279,7 +279,7 @@ def self.process_undocumented_token(doc, declaration) filepath = doc['key.filepath'] objc = Config.instance.objc_mode if objc || should_mark_undocumented(doc['key.kind'], filepath) - @undocumented_decls << declaration + @stats.add_undocumented(declaration) end return nil if !documented_child?(doc) && @skip_undocumented make_default_doc_info(declaration) @@ -319,7 +319,7 @@ def self.make_doc_info(doc, declaration) declaration.return = Markdown.rendered_returns declaration.parameters = parameters(doc, Markdown.rendered_parameters) - @documented_count += 1 + @stats.add_documented end # rubocop:enable Metrics/CyclomaticComplexity # rubocop:enable Metrics/PerceivedComplexity @@ -390,12 +390,6 @@ def self.make_source_declarations(docs, parent = nil) # rubocop:enable Metrics/CyclomaticComplexity # rubocop:enable Metrics/MethodLength - def self.doc_coverage - return 0 if @documented_count == 0 && @undocumented_decls.count == 0 - (100 * @documented_count) / - (@undocumented_decls.count + @documented_count) - end - # Merges multiple extensions of the same entity into a single document. # # Merges extensions into the protocol/class/struct/enum they extend, if it @@ -615,6 +609,7 @@ def self.reject_objc_types(docs) def self.parse(sourcekitten_output, min_acl, skip_undocumented, inject_docs) @min_acl = min_acl @skip_undocumented = skip_undocumented + @stats = Stats.new sourcekitten_json = filter_excluded_files(JSON.parse(sourcekitten_output)) docs = make_source_declarations(sourcekitten_json).concat inject_docs docs = deduplicate_declarations(docs) @@ -629,7 +624,7 @@ def self.parse(sourcekitten_output, min_acl, skip_undocumented, inject_docs) docs = group_docs(docs) make_doc_urls(docs) autolink(docs, ungrouped_docs) - [docs, doc_coverage, @undocumented_decls] + [docs, @stats] end end end diff --git a/lib/jazzy/stats.rb b/lib/jazzy/stats.rb new file mode 100644 index 000000000..e1abf17b9 --- /dev/null +++ b/lib/jazzy/stats.rb @@ -0,0 +1,74 @@ +module Jazzy + # Collect + report metadata about a processed module + class Stats + include Config::Mixin + + attr_reader :documented, :acl_skipped + attr_reader :undocumented_decls + + def add_documented + @documented += 1 + end + + def add_acl_skipped + @acl_skipped += 1 + end + + def add_undocumented(decl) + @undocumented_decls << decl + end + + def acl_included + documented + undocumented_decls.count + end + + def undocumented + undocumented_decls.count + end + + def initialize + @documented = @acl_skipped = 0 + @undocumented_decls = [] + end + + def report + puts "#{doc_coverage}\% documentation coverage " \ + "with #{undocumented} undocumented " \ + "#{symbol_or_symbols(undocumented)}" + + if acl_included > 0 + swift_acls = comma_list(config.min_acl.included_levels) + puts "included #{acl_included} " + + (config.objc_mode ? '' : "#{swift_acls} ") + + symbol_or_symbols(acl_included) + end + + if !config.objc_mode && acl_skipped > 0 + puts "skipped #{acl_skipped} " \ + "#{comma_list(config.min_acl.excluded_levels)} " \ + "#{symbol_or_symbols(acl_skipped)} " \ + '(use `--min_acl` to see)' + end + end + + def doc_coverage + return 0 if acl_included == 0 + (100 * documented) / acl_included + end + + private + + def comma_list(items) + case items.count + when 0 then '' + when 1 then items[0] + when 2 then "#{items[0]} or #{items[1]}" + else "#{items[0..-2].join(', ')}, or #{items[-1]}" + end + end + + def symbol_or_symbols(count) + count == 1 ? 'symbol' : 'symbols' + end + end +end