Module: Wisco::Commands::Schema
- Defined in:
- lib/wisco/commands/schema.rb
Constant Summary collapse
- API_GENERATE_SCHEMA_PATH =
'/api/sdk/generate_schema'- KEY_ORDER =
%w[name label type of control_type convert_input convert_output].freeze
- SYMBOL_VALUE_KEYS =
%w[type of].freeze
Class Method Summary collapse
-
.fetch_schema(input_file, hostname, api_token, col_sep:, debug:) ⇒ Object
── API call ──────────────────────────────────────────────────────────.
-
.format_field(field, base_indent, style) ⇒ Object
Renders a single field hash.
-
.format_json(schema) ⇒ Object
── JSON output ───────────────────────────────────────────────────────.
-
.format_ruby(schema, style:) ⇒ Object
Renders the top-level schema array as a Ruby literal.
-
.format_ruby_array(fields, indent, style) ⇒ Object
Renders a properties array (a list of nested fields) at the given indent.
-
.resolve_output_path(output, input_file, format) ⇒ Object
Resolves the output file path from the –output option value.
-
.ruby_scalar(key, value) ⇒ Object
Returns the Ruby literal string for a scalar value.
- .run(input_file, target_dir, format:, ruby_options:, col_sep:, output:, debug:) ⇒ Object
-
.wrap_if_array(json_content) ⇒ Object
If the JSON content is a top-level array, wrap it in […] so the Workato API accepts it (it requires a top-level object).
Class Method Details
.fetch_schema(input_file, hostname, api_token, col_sep:, debug:) ⇒ Object
── API call ──────────────────────────────────────────────────────────
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 105 106 107 108 109 110 111 112 |
# File 'lib/wisco/commands/schema.rb', line 79 def fetch_schema(input_file, hostname, api_token, col_sep:, debug:) ext = File.extname(input_file).delete_prefix('.') # 'json' or 'csv' url = "https://#{hostname}#{API_GENERATE_SCHEMA_PATH}/#{ext}" sample = File.read(input_file) sample = wrap_if_array(sample) if ext == 'json' payload = { sample: sample } payload[:col_sep] = col_sep if ext == 'csv' if debug warn "[schema] url: #{url}" warn "[schema] col_sep: #{col_sep}" if ext == 'csv' end response = RestClient.post( url, payload.to_json, content_type: :json, accept: :json, 'Authorization' => "Bearer #{api_token}" ) JSON.parse(response.body) rescue RestClient::ExceptionWithResponse => e msg = begin JSON.parse(e.response.body)['message'] rescue StandardError e. end Wisco::TerminalOutput.emit_error("Error generating schema: #{msg}") exit 1 rescue StandardError => e Wisco::TerminalOutput.emit_error("Error generating schema: #{e.}") exit 1 end |
.format_field(field, base_indent, style) ⇒ Object
Renders a single field hash. Recursively handles nested ‘properties`.
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/wisco/commands/schema.rb', line 145 def format_field(field, base_indent, style) # Reorder keys: KEY_ORDER first, then any extras; pull properties out separately ordered = KEY_ORDER.select { |k| field.key?(k) } extras = field.keys - KEY_ORDER - ['properties'] pairs = (ordered + extras).map { |k| [k, field[k]] } props = field['properties'] cont_indent = base_indent + 2 # continuation indent (aligns keys after "{ ") prop_indent = base_indent + 4 # properties array indent if style == :single_line kv_str = pairs.map { |k, v| "#{k}: #{ruby_scalar(k, v)}" }.join(', ') if props prop_lines = format_ruby_array(props, prop_indent, style) "{ #{kv_str}, properties:\n#{prop_lines}\n#{' ' * base_indent}}" else "{ #{kv_str}}" end else # multi_line: first pair on same line as {, rest on new lines kv_lines = pairs.map { |k, v| "#{k}: #{ruby_scalar(k, v)}" } first = kv_lines.shift if kv_lines.empty? && !props # Single pair, no properties "{ #{first}}" elsif props rest = kv_lines.map { |l| "#{' ' * cont_indent}#{l}" } prop_line = "#{' ' * cont_indent}properties:" prop_lines = format_ruby_array(props, prop_indent, style) parts = ["{ #{first}"] + rest + [prop_line] "#{parts.join(",\n")}\n#{prop_lines}\n#{' ' * base_indent}}" else rest = kv_lines.map { |l| "#{' ' * cont_indent}#{l}" } parts = ["{ #{first}"] + rest "#{parts.join(",\n")}}" end end end |
.format_json(schema) ⇒ Object
── JSON output ───────────────────────────────────────────────────────
130 131 132 |
# File 'lib/wisco/commands/schema.rb', line 130 def format_json(schema) JSON.pretty_generate(schema) end |
.format_ruby(schema, style:) ⇒ Object
Renders the top-level schema array as a Ruby literal.
137 138 139 140 141 142 |
# File 'lib/wisco/commands/schema.rb', line 137 def format_ruby(schema, style:) indent = 4 items = schema.map { |field| format_field(field, indent, style) } inner = items.map { |item| "#{' ' * indent}#{item}" }.join(",\n") "[\n#{inner}\n]" end |
.format_ruby_array(fields, indent, style) ⇒ Object
Renders a properties array (a list of nested fields) at the given indent. The opening/closing brackets sit at ‘indent` spaces; items are indented a further 4 spaces inside the brackets.
189 190 191 192 193 194 |
# File 'lib/wisco/commands/schema.rb', line 189 def format_ruby_array(fields, indent, style) item_indent = indent + 4 items = fields.map { |f| format_field(f, item_indent, style) } inner = items.map { |item| "#{' ' * item_indent}#{item}" }.join(",\n") "#{' ' * indent}[\n#{inner}\n#{' ' * indent}]" end |
.resolve_output_path(output, input_file, format) ⇒ Object
Resolves the output file path from the –output option value.
nil → no --output flag; return nil (print to stdout)
'' → --output with no value; derive from input_file + format
other → explicit path; expand and use as-is
64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/wisco/commands/schema.rb', line 64 def resolve_output_path(output, input_file, format) return nil if output.nil? if output.empty? file_ext = format == 'json' ? '.json' : '.rb' dir = File.dirname(input_file) base = File.basename(input_file, '.*') File.join(dir, "#{base}.schema#{file_ext}") else File.(output) end end |
.ruby_scalar(key, value) ⇒ Object
Returns the Ruby literal string for a scalar value.
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/wisco/commands/schema.rb', line 197 def ruby_scalar(key, value) if SYMBOL_VALUE_KEYS.include?(key) && value.is_a?(String) ":#{value}" elsif value.is_a?(String) "'#{value.gsub('\\', '\\\\\\\\').gsub("'", "\\\\'")}'" elsif value.nil? 'nil' elsif value == true || value == false value.to_s elsif value.is_a?(Numeric) value.to_s else value.inspect end end |
.run(input_file, target_dir, format:, ruby_options:, col_sep:, output:, debug:) ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/wisco/commands/schema.rb', line 15 def run(input_file, target_dir, format:, ruby_options:, col_sep:, output:, debug:) input_file = File.(input_file) target_dir = File.(target_dir) unless File.exist?(input_file) Wisco::TerminalOutput.emit_error("Error: Input file not found: #{input_file}") exit 1 end ext = File.extname(input_file).downcase unless %w[.json .csv].include?(ext) Wisco::TerminalOutput.emit_error("Error: Unsupported file type '#{ext}'. Must be .json or .csv.") exit 1 end config_path = Wisco.config_path(target_dir) unless File.exist?(config_path) Wisco::TerminalOutput.emit_error("Error: No #{Wisco::WISCO_DIR}/#{Wisco::CONFIG_FILENAME} found in #{target_dir}.") Wisco::TerminalOutput.emit_error(" Run '#{Wisco::CLI_NAME} init' first.") exit 1 end config = Wisco::Config.load_config(config_path) config = Wisco::Config.ensure_api_config(config, config_path) hostname = config.dig('workato_developer_api', 'hostname') api_token = config.dig('workato_developer_api', 'api_token') schema = fetch_schema(input_file, hostname, api_token, col_sep: col_sep, debug: debug) formatted = if format == 'json' format_json(schema) else format_ruby(schema, style: .to_sym) end output_path = resolve_output_path(output, input_file, format) if output_path File.write(output_path, formatted + "\n") puts "Written: #{output_path}" else puts formatted end end |
.wrap_if_array(json_content) ⇒ Object
If the JSON content is a top-level array, wrap it in […] so the Workato API accepts it (it requires a top-level object). Returns the (possibly modified) JSON string; never modifies the source file.
117 118 119 120 121 122 123 124 125 126 |
# File 'lib/wisco/commands/schema.rb', line 117 def wrap_if_array(json_content) parsed = JSON.parse(json_content) return json_content unless parsed.is_a?(Array) Wisco::TerminalOutput.emit_info('[INFO] Input JSON is a top-level array.') Wisco::TerminalOutput.emit_info('[INFO] Wrapping in {"input": [...]} for Workato API compatibility.') JSON.generate({ 'input' => parsed }) rescue JSON::ParseError json_content # unparseable — send as-is and let the API report the error end |