wisco 0.3.4 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce64641188dfbd354a2279042c813975e03a309f78e289b8d1fc72a33e748d6f
4
- data.tar.gz: c3b602c65d2a4c7e8eb45664a063c863834978309d8e831d81b316f245eb62ad
3
+ metadata.gz: f7db313badb869b62a2bf9eab0b4558cecffe8946bb8acaa0664cb4d65e3641f
4
+ data.tar.gz: fa68ec90e00dec3934be909a3f9b5cb122bd93a8dac3801733eba4f066f2f4f4
5
5
  SHA512:
6
- metadata.gz: 7960efd667edfc41ada2e9ec7e646004e83f81270a12669ba2281b25c1d9f6d179da449137b811f616f9c413e8273bf973cf74bf0f3dbfeafe2e85cbc8980048
7
- data.tar.gz: 688ee858d3d5245d41e0c78dbfd5766b3d6e82561f052af3a7726e343f9b64cbf7113d81fe72cf11e745dd9b75480d7a4d4ffca6e5fd4eb806286f5e1eac3841
6
+ metadata.gz: be79dffcc14ff47e9333e175a0f6c967c28646045ba35094bde7740903b9d64a44a510c98f47ff676b4baf902c651de7bf4beda8b4e0d69f61bc03411e861b41
7
+ data.tar.gz: 5340d7f07bd891bc4ac456a576749cffe1cb948df63af61dbe0192e22d92393d4a61b4c3bdb5d642b99446a1af96a48df0d782394728f2b19fda78d4428ef75d
data/bin/wisco CHANGED
File without changes
File without changes
@@ -4,7 +4,9 @@
4
4
  # Workato SDK files
5
5
  master.key
6
6
 
7
- # Exclude error files from fixtures
7
+ # wisco fixtures
8
+ fixtures/connection/test/output_test.json
9
+ fixtures/actions/*/execute*.json
8
10
  fixtures/*/*/error*.txt
9
11
 
10
12
  # Exclude local working data
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,214 @@
1
+ require 'rest-client'
2
+ require 'json'
3
+ require_relative '../config'
4
+ require_relative '../terminal_output'
5
+
6
+ module Wisco
7
+ module Commands
8
+ module Schema
9
+ API_GENERATE_SCHEMA_PATH = '/api/sdk/generate_schema'
10
+ KEY_ORDER = %w[name label type of control_type convert_input convert_output].freeze
11
+ SYMBOL_VALUE_KEYS = %w[type of].freeze
12
+
13
+ module_function
14
+
15
+ def run(input_file, target_dir, format:, ruby_options:, col_sep:, output:, debug:)
16
+ input_file = File.expand_path(input_file)
17
+ target_dir = File.expand_path(target_dir)
18
+
19
+ unless File.exist?(input_file)
20
+ Wisco::TerminalOutput.emit_error("Error: Input file not found: #{input_file}")
21
+ exit 1
22
+ end
23
+
24
+ ext = File.extname(input_file).downcase
25
+ unless %w[.json .csv].include?(ext)
26
+ Wisco::TerminalOutput.emit_error("Error: Unsupported file type '#{ext}'. Must be .json or .csv.")
27
+ exit 1
28
+ end
29
+
30
+ config_path = Wisco.config_path(target_dir)
31
+ unless File.exist?(config_path)
32
+ Wisco::TerminalOutput.emit_error("Error: No #{Wisco::WISCO_DIR}/#{Wisco::CONFIG_FILENAME} found in #{target_dir}.")
33
+ Wisco::TerminalOutput.emit_error(" Run '#{Wisco::CLI_NAME} init' first.")
34
+ exit 1
35
+ end
36
+
37
+ config = Wisco::Config.load_config(config_path)
38
+ config = Wisco::Config.ensure_api_config(config, config_path)
39
+ hostname = config.dig('workato_developer_api', 'hostname')
40
+ api_token = config.dig('workato_developer_api', 'api_token')
41
+
42
+ schema = fetch_schema(input_file, hostname, api_token, col_sep: col_sep, debug: debug)
43
+
44
+ formatted = if format == 'json'
45
+ format_json(schema)
46
+ else
47
+ format_ruby(schema, style: ruby_options.to_sym)
48
+ end
49
+
50
+ output_path = resolve_output_path(output, input_file, format)
51
+
52
+ if output_path
53
+ File.write(output_path, formatted + "\n")
54
+ puts "Written: #{output_path}"
55
+ else
56
+ puts formatted
57
+ end
58
+ end
59
+
60
+ # Resolves the output file path from the --output option value.
61
+ # nil → no --output flag; return nil (print to stdout)
62
+ # '' → --output with no value; derive from input_file + format
63
+ # other → explicit path; expand and use as-is
64
+ def resolve_output_path(output, input_file, format)
65
+ return nil if output.nil?
66
+
67
+ if output.empty?
68
+ file_ext = format == 'json' ? '.json' : '.rb'
69
+ dir = File.dirname(input_file)
70
+ base = File.basename(input_file, '.*')
71
+ File.join(dir, "#{base}.schema#{file_ext}")
72
+ else
73
+ File.expand_path(output)
74
+ end
75
+ end
76
+
77
+ # ── API call ──────────────────────────────────────────────────────────
78
+
79
+ def fetch_schema(input_file, hostname, api_token, col_sep:, debug:)
80
+ ext = File.extname(input_file).delete_prefix('.') # 'json' or 'csv'
81
+ url = "https://#{hostname}#{API_GENERATE_SCHEMA_PATH}/#{ext}"
82
+ sample = File.read(input_file)
83
+ sample = wrap_if_array(sample) if ext == 'json'
84
+
85
+ payload = { sample: sample }
86
+ payload[:col_sep] = col_sep if ext == 'csv'
87
+
88
+ if debug
89
+ warn "[schema] url: #{url}"
90
+ warn "[schema] col_sep: #{col_sep}" if ext == 'csv'
91
+ end
92
+
93
+ response = RestClient.post(
94
+ url,
95
+ payload.to_json,
96
+ content_type: :json,
97
+ accept: :json,
98
+ 'Authorization' => "Bearer #{api_token}"
99
+ )
100
+ JSON.parse(response.body)
101
+ rescue RestClient::ExceptionWithResponse => e
102
+ msg = begin
103
+ JSON.parse(e.response.body)['message']
104
+ rescue StandardError
105
+ e.message
106
+ end
107
+ Wisco::TerminalOutput.emit_error("Error generating schema: #{msg}")
108
+ exit 1
109
+ rescue StandardError => e
110
+ Wisco::TerminalOutput.emit_error("Error generating schema: #{e.message}")
111
+ exit 1
112
+ end
113
+
114
+ # If the JSON content is a top-level array, wrap it in {"input": [...]}
115
+ # so the Workato API accepts it (it requires a top-level object).
116
+ # Returns the (possibly modified) JSON string; never modifies the source file.
117
+ def wrap_if_array(json_content)
118
+ parsed = JSON.parse(json_content)
119
+ return json_content unless parsed.is_a?(Array)
120
+
121
+ Wisco::TerminalOutput.emit_info('[INFO] Input JSON is a top-level array.')
122
+ Wisco::TerminalOutput.emit_info('[INFO] Wrapping in {"input": [...]} for Workato API compatibility.')
123
+ JSON.generate({ 'input' => parsed })
124
+ rescue JSON::ParseError
125
+ json_content # unparseable — send as-is and let the API report the error
126
+ end
127
+
128
+ # ── JSON output ───────────────────────────────────────────────────────
129
+
130
+ def format_json(schema)
131
+ JSON.pretty_generate(schema)
132
+ end
133
+
134
+ # ── Ruby output ───────────────────────────────────────────────────────
135
+
136
+ # Renders the top-level schema array as a Ruby literal.
137
+ def format_ruby(schema, style:)
138
+ indent = 4
139
+ items = schema.map { |field| format_field(field, indent, style) }
140
+ inner = items.map { |item| "#{' ' * indent}#{item}" }.join(",\n")
141
+ "[\n#{inner}\n]"
142
+ end
143
+
144
+ # Renders a single field hash. Recursively handles nested `properties`.
145
+ def format_field(field, base_indent, style)
146
+ # Reorder keys: KEY_ORDER first, then any extras; pull properties out separately
147
+ ordered = KEY_ORDER.select { |k| field.key?(k) }
148
+ extras = field.keys - KEY_ORDER - ['properties']
149
+ pairs = (ordered + extras).map { |k| [k, field[k]] }
150
+ props = field['properties']
151
+
152
+ cont_indent = base_indent + 2 # continuation indent (aligns keys after "{ ")
153
+ prop_indent = base_indent + 4 # properties array indent
154
+
155
+ if style == :single_line
156
+ kv_str = pairs.map { |k, v| "#{k}: #{ruby_scalar(k, v)}" }.join(', ')
157
+
158
+ if props
159
+ prop_lines = format_ruby_array(props, prop_indent, style)
160
+ "{ #{kv_str}, properties:\n#{prop_lines}\n#{' ' * base_indent}}"
161
+ else
162
+ "{ #{kv_str}}"
163
+ end
164
+ else
165
+ # multi_line: first pair on same line as {, rest on new lines
166
+ kv_lines = pairs.map { |k, v| "#{k}: #{ruby_scalar(k, v)}" }
167
+ first = kv_lines.shift
168
+
169
+ if kv_lines.empty? && !props
170
+ # Single pair, no properties
171
+ "{ #{first}}"
172
+ elsif props
173
+ rest = kv_lines.map { |l| "#{' ' * cont_indent}#{l}" }
174
+ prop_line = "#{' ' * cont_indent}properties:"
175
+ prop_lines = format_ruby_array(props, prop_indent, style)
176
+ parts = ["{ #{first}"] + rest + [prop_line]
177
+ "#{parts.join(",\n")}\n#{prop_lines}\n#{' ' * base_indent}}"
178
+ else
179
+ rest = kv_lines.map { |l| "#{' ' * cont_indent}#{l}" }
180
+ parts = ["{ #{first}"] + rest
181
+ "#{parts.join(",\n")}}"
182
+ end
183
+ end
184
+ end
185
+
186
+ # Renders a properties array (a list of nested fields) at the given indent.
187
+ # The opening/closing brackets sit at `indent` spaces; items are indented
188
+ # a further 4 spaces inside the brackets.
189
+ def format_ruby_array(fields, indent, style)
190
+ item_indent = indent + 4
191
+ items = fields.map { |f| format_field(f, item_indent, style) }
192
+ inner = items.map { |item| "#{' ' * item_indent}#{item}" }.join(",\n")
193
+ "#{' ' * indent}[\n#{inner}\n#{' ' * indent}]"
194
+ end
195
+
196
+ # Returns the Ruby literal string for a scalar value.
197
+ def ruby_scalar(key, value)
198
+ if SYMBOL_VALUE_KEYS.include?(key) && value.is_a?(String)
199
+ ":#{value}"
200
+ elsif value.is_a?(String)
201
+ "'#{value.gsub('\\', '\\\\\\\\').gsub("'", "\\\\'")}'"
202
+ elsif value.nil?
203
+ 'nil'
204
+ elsif value == true || value == false
205
+ value.to_s
206
+ elsif value.is_a?(Numeric)
207
+ value.to_s
208
+ else
209
+ value.inspect
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
data/lib/wisco/config.rb CHANGED
File without changes
File without changes
File without changes
File without changes
data/lib/wisco/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Wisco
2
- VERSION = '0.3.4'
2
+ VERSION = '0.3.5'
3
3
  end
File without changes
data/lib/wisco.rb CHANGED
@@ -22,6 +22,7 @@ require_relative 'wisco/commands/exec'
22
22
  require_relative 'wisco/commands/fixtures'
23
23
  require_relative 'wisco/commands/pull'
24
24
  require_relative 'wisco/commands/push'
25
+ require_relative 'wisco/commands/schema'
25
26
 
26
27
  module Wisco
27
28
  class CLI < Thor
@@ -177,5 +178,37 @@ module Wisco
177
178
  debug: options[:debug]
178
179
  )
179
180
  end
181
+
182
+ desc 'schema INPUT_FILE [TARGET_DIR]', 'Generate a schema from a JSON or CSV sample file'
183
+ long_desc <<~DESC
184
+ Calls the Workato API to generate a schema from a sample JSON or CSV file.
185
+ File type is auto-detected from the extension (.json or .csv).
186
+ Output defaults to Ruby hash format; use --format=json for raw JSON.
187
+
188
+ Requires workato_developer_api hostname and api_token in #{WISCO_DIR}/#{CONFIG_FILENAME}.
189
+ If not set, you will be prompted on first run.
190
+ DESC
191
+ option :format, type: :string, default: 'ruby', enum: %w[ruby json],
192
+ desc: 'Output format: ruby (default) or json'
193
+ option :ruby_options, type: :string, default: 'multi_line', enum: %w[single_line multi_line],
194
+ desc: 'Ruby output style: single_line or multi_line (default)'
195
+ option :'col-sep', type: :string, default: 'comma',
196
+ enum: %w[comma space tab colon semicolon pipe],
197
+ desc: 'CSV column separator (default: comma)'
198
+ option :save, type: :string, lazy_default: '',
199
+ desc: 'Save output to file. Omit value to auto-name from input file ' \
200
+ '(e.g. input.json → input.schema.rb / input.schema.json)'
201
+ option :debug, type: :boolean, default: false, desc: 'Show API call details'
202
+ def schema(input_file, target_dir = nil)
203
+ Wisco::Commands::Schema.run(
204
+ input_file,
205
+ target_dir || Dir.pwd,
206
+ format: options[:format],
207
+ ruby_options: options[:ruby_options],
208
+ col_sep: options[:col_sep],
209
+ output: options[:save],
210
+ debug: options[:debug]
211
+ )
212
+ end
180
213
  end
181
214
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wisco
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - mbillington
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-28 00:00:00.000000000 Z
11
+ date: 2026-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -73,6 +73,7 @@ files:
73
73
  - lib/wisco/commands/list.rb
74
74
  - lib/wisco/commands/pull.rb
75
75
  - lib/wisco/commands/push.rb
76
+ - lib/wisco/commands/schema.rb
76
77
  - lib/wisco/config.rb
77
78
  - lib/wisco/connector.rb
78
79
  - lib/wisco/path_utils.rb