# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2020-2024, by Samuel Williams.

def initialize(...)
	super
	
	require 'decode/index'
	require 'set'
end

# Process the given source root and report on comment coverage.
# @parameter root [String] The root path to index.
def coverage(root)
	paths = Dir.glob(File.join(root, "**/*"))
	
	index = Decode::Index.new
	index.update(paths)
	
	documented = Set.new
	missing = Set.new
	
	index.trie.traverse do |path, node, descend|
		public_definition = node.values.nil?
		
		node.values&.each do |definition|
			if definition.public?
				level = path.size
				
				if definition.comments.nil?
					missing << definition.qualified_name
				else
					documented << definition.qualified_name
				end
				
				public_definition = true
			end
		end
		
		# Don't descend into non-public definitions:
		if public_definition
			descend.call
		end
	end
	
	# Since there can be multiple definitions for a given symbol, we can ignore any missing definitions that have been documented elsewhere:
	missing = missing - documented
	
	documented_count = documented.size
	public_count = documented_count + missing.size
	$stderr.puts "#{documented_count} definitions have documentation, out of #{public_count} public definitions."
	
	if documented_count < public_count
		$stderr.puts nil, "Missing documentation for:"
		missing.each do |name|
			$stderr.puts "- #{name}"
		end
		
		raise RuntimeError, "Insufficient documentation!"
	end
end

# Process the given source root and report on symbols.
# @parameter root [String] The root path to index.
def symbols(root)
	paths = Dir.glob(File.join(root, "**/*"))
	
	index = Decode::Index.new
	index.update(paths)
	
	index.trie.traverse do |path, node, descend|
		level = path.size
		puts "#{"  " * level}#{path.inspect} -> #{node.values.inspect}"
		
		if path.any?
			puts "#{"  " * level}#{path.join("::")}"
		end
		
		descend.call
	end
end

# Print documentation for all definitions.
# @parameter root [String] The root path to index.
def documentation(root)
	paths = Dir.glob(File.join(root, "**/*"))
	
	index = Decode::Index.new
	index.update(paths)
	
	index.definitions.each do |name, definition|
		comments = definition.comments
		
		if comments
			puts "## `#{name}`"
			puts
			puts comments
			puts
		end
	end
end
