#!/usr/bin/env ruby # coding: utf-8 # gendoc.rb -- Converts the top-comments inside module.c to modules API # reference documentation in markdown format. # Convert the C comment to markdown def markdown(s) s = s.gsub(/\*\/$/,"") s = s.gsub(/^ ?\* ?/,"") s = s.gsub(/^\/\*\*? ?/,"") s.chop! while s[-1] == "\n" || s[-1] == " " lines = s.split("\n") newlines = [] # Fix some markdown lines.each{|l| # Rewrite VM_Xyz() to ValkeyModule_Xyz(). l = l.gsub(/(?\n\n" puts "### `#{name}`\n\n" puts " #{proto}\n" puts "**Available since:** #{$since[shortname] or "unreleased"}\n\n" comment = "" while true i = i-1 comment = src[i]+comment break if src[i] =~ /\/\*/ end comment = markdown(comment) puts comment+"\n\n" end # Print a comment from line until */ is found, as markdown. def section_doc(src, i) name = get_section_heading(src, i) comment = "\n\n" while true # append line, except if it's a horizontal divider comment = comment + src[i] if src[i] !~ /^[\/ ]?\*{1,2} ?-{50,}/ break if src[i] =~ /\*\// i = i+1 end comment = markdown(comment) puts comment+"\n\n" end # generates an id suitable for links within the page def section_name_to_id(name) return "section-" + name.strip.downcase.gsub(/[^a-z0-9]+/, '-').gsub(/^-+|-+$/, '') end # Returns the name of the first section heading in the comment block for which # is_section_doc(src, i) is true def get_section_heading(src, i) if src[i] =~ /^\/\*\*? \#+ *(.*)/ heading = $1 elsif src[i+1] =~ /^ ?\* \#+ *(.*)/ heading = $1 end return heading.gsub(' -- ', ' – ') end # Returns true if the line is the start of a generic documentation section. Such # section must start with the # symbol, i.e. a markdown heading, on the first or # the second line. def is_section_doc(src, i) return src[i] =~ /^\/\*\*? \#/ || (src[i] =~ /^\/\*/ && src[i+1] =~ /^ ?\* \#/) end def is_func_line(src, i) line = src[i] return line =~ /VM_/ && line[0] != ' ' && line[0] != '#' && line[0] != '/' && src[i-1] =~ /\*\// end puts "---\n" puts "title: \"Modules API reference\"\n" puts "linkTitle: \"API reference\"\n" puts "description: >\n" puts " Reference for the Valkey Modules API\n" puts "---\n" puts "\n" puts "\n\n" src = File.open(File.dirname(__FILE__) ++ "/../src/module.c").to_a # Build function index $index = {} src.each_with_index do |line,i| if is_func_line(src, i) line =~ /VM_([A-z0-9]+)/ name = "ValkeyModule_#{$1}" $index[name] = true end end # Populate the 'since' map (name => version) if we're in a git repo. require "./" ++ File.dirname(__FILE__) ++ '/module-api-since.rb' git_dir = File.dirname(__FILE__) ++ "/../.git" if File.directory?(git_dir) && `which git` != "" `git --git-dir="#{git_dir}" tag --sort=v:refname`.each_line do |version| next if version !~ /^(\d+)\.\d+\.\d+?$/ || $1.to_i < 4 version.chomp! `git --git-dir="#{git_dir}" cat-file blob "#{version}:src/module.c"`.each_line do |line| if line =~ /^\w.*[ \*]VM_([A-z0-9]+)/ name = $1 if ! $since[name] $since[name] = version end end end end end # Print TOC puts "## Sections\n\n" src.each_with_index do |_line,i| if is_section_doc(src, i) name = get_section_heading(src, i) puts "* [#{name}](\##{section_name_to_id(name)})\n" end end puts "* [Function index](#section-function-index)\n\n" # Docufy: Print function prototype and markdown docs src.each_with_index do |_line,i| if is_func_line(src, i) docufy(src, i) elsif is_section_doc(src, i) section_doc(src, i) end end # Print function index puts "\n\n" puts "## Function index\n\n" $index.keys.sort.each{|x| puts "* [`#{x}`](\##{x})\n"} puts "\n"