|
| 1 | +# typed: true |
| 2 | +# frozen_string_literal: true |
| 3 | + |
| 4 | +require "yard" |
| 5 | +require "tapioca" |
| 6 | +require "tapioca/runtime/reflection" |
| 7 | + |
| 8 | +YARD::Rake::YardocTask.new(:yard_for_generate_documentation) do |task| |
| 9 | + task.files = ["lib/tapioca/dsl/compilers/**/*.rb"] |
| 10 | + task.options = ["--no-output"] |
| 11 | +end |
| 12 | + |
| 13 | +desc("Generate docs of all DSL compilers") |
| 14 | +task generate_dsl_documentation: :yard_for_generate_documentation do |
| 15 | + def assert_manual_synchronized |
| 16 | + # Do not print diff and yield whether exit code was zero |
| 17 | + sh('test -z "$(git status --porcelain manual)"') do |outcome, _| |
| 18 | + return if outcome |
| 19 | + |
| 20 | + # Output diff before raising error |
| 21 | + sh("git status --porcelain manual") |
| 22 | + |
| 23 | + warn(<<~WARNING) |
| 24 | + The manual directory is out of sync. |
| 25 | + Run `bin/docs` (or `dev docs`) and commit the results. |
| 26 | + WARNING |
| 27 | + |
| 28 | + exit! |
| 29 | + end |
| 30 | + end |
| 31 | + |
| 32 | + def table_contents(registry) |
| 33 | + registry |
| 34 | + .filter_map do |entry| |
| 35 | + "* #{entry.link}" |
| 36 | + end |
| 37 | + .join("\n") |
| 38 | + end |
| 39 | + |
| 40 | + def print_table_of_contents(registry) |
| 41 | + path = "#{Dir.pwd}/manual/compilers.md" |
| 42 | + original = File.read(path) |
| 43 | + content = +"<!-- START_COMPILER_LIST -->\n" |
| 44 | + |
| 45 | + content << table_contents(registry) |
| 46 | + |
| 47 | + content << "\n<!-- END_COMPILER_LIST -->" |
| 48 | + |
| 49 | + content = if original.empty? |
| 50 | + content |
| 51 | + else |
| 52 | + original.sub( |
| 53 | + /<!-- START_COMPILER_LIST -->.+<!-- END_COMPILER_LIST -->/m, content |
| 54 | + ) |
| 55 | + end |
| 56 | + File.write(path, content) |
| 57 | + end |
| 58 | + |
| 59 | + def compiler_body(registry_entry) |
| 60 | + content = +"## #{registry_entry.name}\n" |
| 61 | + content << "\n" |
| 62 | + content << "#{registry_entry.description}\n" |
| 63 | + content |
| 64 | + end |
| 65 | + |
| 66 | + def print_compilers(registry) |
| 67 | + registry.each do |entry| |
| 68 | + File.write(entry.filename, compiler_body(entry)) |
| 69 | + end |
| 70 | + end |
| 71 | + |
| 72 | + def load_registry |
| 73 | + YARD::Registry.all(:class).filter_map do |code_object| |
| 74 | + next unless code_object.superclass.to_s == "Tapioca::Dsl::Compiler" |
| 75 | + |
| 76 | + RegistryEntry.new(code_object.name.to_s, code_object) |
| 77 | + end.sort_by(&:name) |
| 78 | + end |
| 79 | + |
| 80 | + RegistryEntry = Struct.new(:name, :code_object) do |
| 81 | + def filename |
| 82 | + "#{Dir.pwd}/manual/compiler_#{name.downcase}.md" |
| 83 | + end |
| 84 | + |
| 85 | + def filebasename |
| 86 | + File.basename(filename) |
| 87 | + end |
| 88 | + |
| 89 | + def link |
| 90 | + "[#{name}](#{filebasename})" |
| 91 | + end |
| 92 | + |
| 93 | + def description |
| 94 | + if code_object.docstring.blank? |
| 95 | + "[No description provided]" |
| 96 | + else |
| 97 | + code_object.docstring |
| 98 | + end |
| 99 | + end |
| 100 | + end |
| 101 | + |
| 102 | + def main |
| 103 | + Dir.glob("lib/tapioca/dsl/{compiler.rb,compilers/**/*.rb}") { |file| YARD.parse(file) } |
| 104 | + registry = load_registry |
| 105 | + |
| 106 | + print_table_of_contents(registry) |
| 107 | + print_compilers(registry) |
| 108 | + |
| 109 | + assert_manual_synchronized if ENV["CI"] == "true" |
| 110 | + end |
| 111 | + |
| 112 | + main |
| 113 | +end |
0 commit comments