Class: Aspera::Schema::Documentation

Inherits:
Object
  • Object
show all
Defined in:
lib/aspera/schema/documentation.rb

Overview

Generate documentation from Schema, for Transfer Spec, or async Conf spec

Instance Method Summary collapse

Constructor Details

#initialize(formatter, schema, include_option: false, agent_columns: false, code_highlight: false) ⇒ Documentation

Returns a new instance of Documentation.

Parameters:

  • formatter (Cli::Formatter)

    Formatter instance with methods: markdown_text, tick, check_row

  • schema (Reader)
  • include_option (Boolean) (defaults to: false)

    ‘true`: include CLI options (switches, env vars) in descriptions

  • agent_columns (Boolean) (defaults to: false)

    ‘true`: add separate columns for each transfer agent compatibility

  • code_highlight (Boolean) (defaults to: false)

    ‘true`: format name and type as code



15
16
17
18
19
20
21
22
23
24
25
# File 'lib/aspera/schema/documentation.rb', line 15

def initialize(formatter, schema, include_option: false, agent_columns: false, code_highlight: false)
  @formatter = formatter
  @schema = schema
  @include_option = include_option
  @agent_columns = agent_columns
  @code_highlight = code_highlight
  @columns = %i[name type description]
  @columns.insert(-2, *Agent::Factory::ALL.values.map{ |i| i[:short]}.sort) if @agent_columns
  # @type [Array<Hash<Symbol,String>>]
  @rows = []
end

Instance Method Details

#build(schema = nil) ⇒ Documentation

Generate a documentation table from a JSON schema for transfer specifications

Recursively processes a JSON schema to create a formatted table for manual documentation. Handles nested objects, arrays, and extracts metadata (descriptions, types, enums, deprecations).

Parameters:

  • schema (Reader) (defaults to: nil)

    The JSON schema to process

Returns:



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/aspera/schema/documentation.rb', line 49

def build(schema = nil)
  code = @code_highlight ? ->(c){"`#{c}`"} : ->(c){c}
  schema ||= @schema
  schema.each_property do |property_schema, _name, property_full_name|
    node = property_schema.current
    # Manual table
    item = {
      name:        code.call(property_full_name),
      type:        code.call(node['type']),
      description: []
    }
    # Render Markdown formatting and split lines
    item[:description] =
      node['description']
        .gsub(Markdown::FORMATS){@formatter.markdown_text(Regexp.last_match)}
        .split("\n") if node.key?('description')
    item[:description].unshift("DEPRECATED: #{node['x-deprecation']}") if node.key?('x-deprecation')
    # Add flags for supported agents in doc
    agents = []
    Agent::Factory::ALL.each_key do |sym|
      agents.push(sym) if node['x-agents'].nil? || node['x-agents'].include?(sym.to_s)
    end
    Aspera.assert(agents.include?(:direct)){"#{name}: x-cli-option requires agent direct (or nil)"} if node['x-cli-option']
    if @agent_columns
      Agent::Factory::ALL.each do |sym, names|
        item[names[:short]] = @formatter.tick(agents.include?(sym))
      end
    else
      item[:description].push("(#{agents.map{ |i| Agent::Factory::ALL[i][:short].to_s.upcase}.sort.join(', ')})") unless agents.length.eql?(Agent::Factory::ALL.length)
    end
    # Only keep lines that are usable in supported agents
    next false if agents.empty?
    item[:description].push("Allowed values: #{node['enum'].map{ |v| @formatter.markdown_text("`#{v}`")}.join(', ')}.") if node.key?('enum')
    item[:description].push("Default: #{code.call(node['default'])}.") if node.key?('default')
    if @include_option
      envvar_prefix = ''
      cli_option =
        if node.key?('x-cli-envvar')
          envvar_prefix = 'env:'
          node['x-cli-envvar']
        elsif node['x-cli-switch']
          node['x-cli-option']
        elsif node['x-cli-option']
          arg_type = node.key?('enum') ? '{enum}' : "{#{[node['type']].flatten.join('|')}}"
          # conversion_tag = node['x-cli-convert']
          conversion_tag = node.key?('x-cli-convert') ? 'conversion' : nil
          sep = node['x-cli-option'].start_with?('--') ? '=' : ' '
          "#{node['x-cli-option']}#{sep}#{"(#{conversion_tag})" if conversion_tag}#{arg_type}"
        end
      short = node.key?('x-cli-short') ? "(#{node['x-cli-short']})" : nil
      item[:description].push("(#{'special:' if node['x-cli-special']}#{envvar_prefix}#{@formatter.markdown_text("`#{cli_option}`")})#{short}") if cli_option
    end
    @rows.push(@formatter.check_row(item))
  end
  self
end

#columnsArray<String>

Returns:



32
33
34
# File 'lib/aspera/schema/documentation.rb', line 32

def columns
  @columns.map(&:to_s)
end

#rowsObject



27
28
29
# File 'lib/aspera/schema/documentation.rb', line 27

def rows
  @rows.sort_by{ |i| i[:name]}
end

#tableArray<Array<String>>

First row is the titles

Returns:



38
39
40
# File 'lib/aspera/schema/documentation.rb', line 38

def table
  [@columns.map(&:to_s)] + @rows.sort_by{ |i| i[:name]}.map{ |row| @columns.map{ |field| row[field]}}
end