poke-your-api 0.4.1 → 0.4.2
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 +4 -4
- data/lib/poke/cli.rb +2 -0
- data/lib/poke/commands/curl.rb +10 -0
- data/lib/poke/curl_parser.rb +215 -14
- data/lib/poke/version.rb +1 -1
- metadata +3 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2b1af586770454d02923775c16441dddcd89fe5a1f548963c2b4bf1e413c980f
|
|
4
|
+
data.tar.gz: 0d069e7c30c835b3a7c6d8bdb8a71a8028aa918af7901b3d305f84688579f801
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: be055ccc527d773f94b12dcc5d9dbe8eb014a45a290fc232511dffe32eef3eedf8c7ca2c27f63446e810e9f1f0ed64b91b3a8017e18d14d7dbf2e99a95f0c98f
|
|
7
|
+
data.tar.gz: 51f82084918632f89ba63722519f9503628fb48f5f2783d88a55c3b3b93f874158d42404448b96240ba08a7548b209ff83634cafc2de6d2cf9ae4523bed18495
|
data/lib/poke/cli.rb
CHANGED
|
@@ -52,6 +52,8 @@ module Poke
|
|
|
52
52
|
method_option :open, aliases: '-o', type: :string, desc: 'Open request in the editor'
|
|
53
53
|
method_option :set_name, aliases: '-N', type: :string, desc: 'Set request name'
|
|
54
54
|
method_option :name, aliases: '-n', type: :string, desc: 'Find request by name'
|
|
55
|
+
method_option :print, aliases: '-p', type: :boolean,
|
|
56
|
+
desc: 'Print a shareable curl command without executing it'
|
|
55
57
|
def curl(*)
|
|
56
58
|
if options[:help]
|
|
57
59
|
invoke :help, ['curl']
|
data/lib/poke/commands/curl.rb
CHANGED
|
@@ -55,6 +55,11 @@ module Poke
|
|
|
55
55
|
env = @options.fetch(:env, request.group.config.default_env)
|
|
56
56
|
raise Poke::GroupConfig::InvalidEnv unless request.group.config.valid_env?(env)
|
|
57
57
|
|
|
58
|
+
if @options[:print]
|
|
59
|
+
print_resolved_curl(request, env, output)
|
|
60
|
+
return
|
|
61
|
+
end
|
|
62
|
+
|
|
58
63
|
curl_command, comments = build_command(request.path)
|
|
59
64
|
|
|
60
65
|
table = TTY::Table.new(
|
|
@@ -97,6 +102,11 @@ module Poke
|
|
|
97
102
|
output << "\n#{File.read(Poke::Config.response_path)}\n"
|
|
98
103
|
end
|
|
99
104
|
|
|
105
|
+
def print_resolved_curl(request, env, output)
|
|
106
|
+
parser = CurlParser.new(File.read(request.path))
|
|
107
|
+
output << "#{parser.to_resolved_command(request.group.config.variables(env), multiline: true)}\n"
|
|
108
|
+
end
|
|
109
|
+
|
|
100
110
|
def build_command(path)
|
|
101
111
|
content = File.read(path)
|
|
102
112
|
parser = CurlParser.new(content)
|
data/lib/poke/curl_parser.rb
CHANGED
|
@@ -10,38 +10,42 @@ module Poke
|
|
|
10
10
|
@content = content
|
|
11
11
|
@comments = []
|
|
12
12
|
@arguments = []
|
|
13
|
+
@tokens = []
|
|
13
14
|
@url = nil
|
|
14
15
|
parse
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def to_command
|
|
18
|
-
|
|
19
|
-
parts.concat(@arguments)
|
|
20
|
-
parts << @url if @url
|
|
21
|
-
parts.join(' ')
|
|
19
|
+
['curl', *@tokens].join(' ')
|
|
22
20
|
end
|
|
23
21
|
|
|
24
22
|
def to_command_with_line_continuation
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
['curl', *@tokens].join(" \\\n ")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Fill in environment variables and shell-quote the result so it can be copied and run without poke.
|
|
27
|
+
# Single-quoted text is left as-is, matching shell expansion rules.
|
|
28
|
+
def to_resolved_command(variables, multiline: false)
|
|
29
|
+
variables = variables.to_h.transform_keys(&:to_s)
|
|
30
|
+
tokens = @tokens.map { |token| expand_shell_word(token, variables) }
|
|
31
|
+
return ['curl', *tokens].join(' ') unless multiline
|
|
32
|
+
|
|
33
|
+
multiline_command(tokens)
|
|
31
34
|
end
|
|
32
35
|
|
|
33
36
|
def add_argument(arg)
|
|
34
37
|
@arguments << arg
|
|
38
|
+
@tokens << arg
|
|
35
39
|
end
|
|
36
40
|
|
|
37
41
|
def remove_argument(pattern)
|
|
38
42
|
@arguments.reject! { |arg| arg.match?(pattern) }
|
|
43
|
+
@tokens.reject! { |arg| arg.match?(pattern) }
|
|
39
44
|
end
|
|
40
45
|
|
|
41
46
|
def replace_argument(pattern, replacement)
|
|
42
|
-
@arguments.map!
|
|
43
|
-
|
|
44
|
-
end
|
|
47
|
+
@arguments.map! { |arg| arg.match?(pattern) ? replacement : arg }
|
|
48
|
+
@tokens.map! { |arg| arg.match?(pattern) ? replacement : arg }
|
|
45
49
|
end
|
|
46
50
|
|
|
47
51
|
private
|
|
@@ -108,6 +112,7 @@ module Poke
|
|
|
108
112
|
args = split_arguments(content)
|
|
109
113
|
|
|
110
114
|
args.each do |arg|
|
|
115
|
+
@tokens << arg
|
|
111
116
|
if arg.start_with?('-')
|
|
112
117
|
@arguments << arg
|
|
113
118
|
elsif @url.nil?
|
|
@@ -119,6 +124,126 @@ module Poke
|
|
|
119
124
|
end
|
|
120
125
|
end
|
|
121
126
|
|
|
127
|
+
def multiline_command(tokens)
|
|
128
|
+
lines = []
|
|
129
|
+
index = 0
|
|
130
|
+
|
|
131
|
+
while index < tokens.length
|
|
132
|
+
token = tokens[index]
|
|
133
|
+
nxt = tokens[index + 1]
|
|
134
|
+
if (body = json_body_line(token, nxt))
|
|
135
|
+
lines << body[:text]
|
|
136
|
+
index += body[:consumed]
|
|
137
|
+
elsif token.start_with?('-') && nxt && !nxt.start_with?('-')
|
|
138
|
+
lines << "#{token} #{nxt}"
|
|
139
|
+
index += 2
|
|
140
|
+
else
|
|
141
|
+
lines << token
|
|
142
|
+
index += 1
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
['curl', *lines].join(" \\\n ")
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def json_body_line(token, nxt)
|
|
150
|
+
flag, value, consumed = split_body_flag(token, nxt)
|
|
151
|
+
return nil unless flag
|
|
152
|
+
|
|
153
|
+
pretty = pretty_json_value(value)
|
|
154
|
+
return nil unless pretty
|
|
155
|
+
|
|
156
|
+
{ text: "#{flag} #{pretty}", consumed: consumed }
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def split_body_flag(token, nxt)
|
|
160
|
+
JSON_BODY_FLAGS.each do |flag|
|
|
161
|
+
return [flag, nxt, 2] if token == flag && nxt && !nxt.start_with?('-')
|
|
162
|
+
|
|
163
|
+
if flag.start_with?('--') && token.start_with?("#{flag}=") && token.length > flag.length + 1
|
|
164
|
+
return [flag, token[(flag.length + 1)..], 1]
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
if flag == '-d' && token.start_with?('-d') && !token.start_with?('--') && token.length > 2
|
|
168
|
+
return ['-d', token[2..], 1]
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
nil
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def pretty_json_value(value)
|
|
175
|
+
raw = unquote_shell(value)
|
|
176
|
+
return nil if raw.nil?
|
|
177
|
+
|
|
178
|
+
parsed = JSON.parse(raw)
|
|
179
|
+
return nil unless parsed.is_a?(Hash) || parsed.is_a?(Array)
|
|
180
|
+
|
|
181
|
+
pretty = JSON.pretty_generate(parsed)
|
|
182
|
+
return nil unless pretty.include?("\n")
|
|
183
|
+
|
|
184
|
+
quote_single(indent_json_block(pretty))
|
|
185
|
+
rescue JSON::ParserError
|
|
186
|
+
nil
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def indent_json_block(pretty)
|
|
190
|
+
pretty.lines.map.with_index { |line, index| index.zero? ? line : " #{line}" }.join
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def quote_single(value)
|
|
194
|
+
"'#{value.gsub("'") { "'\\''" }}'"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def unquote_shell(word)
|
|
198
|
+
if word.start_with?("'")
|
|
199
|
+
decode_single_quoted(word)
|
|
200
|
+
elsif word.start_with?('"') && word.end_with?('"') && word.length >= 2
|
|
201
|
+
decode_double_quoted(word)
|
|
202
|
+
else
|
|
203
|
+
word
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def decode_single_quoted(word)
|
|
208
|
+
result = +''
|
|
209
|
+
index = 1
|
|
210
|
+
return nil unless word[0] == "'"
|
|
211
|
+
|
|
212
|
+
while index < word.length
|
|
213
|
+
if word[index] == "'"
|
|
214
|
+
index += 1
|
|
215
|
+
return result if index == word.length
|
|
216
|
+
return nil unless word[index, 2] == "\\'" && word[index + 2] == "'"
|
|
217
|
+
|
|
218
|
+
result << "'"
|
|
219
|
+
index += 3
|
|
220
|
+
else
|
|
221
|
+
result << word[index]
|
|
222
|
+
index += 1
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
nil
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def decode_double_quoted(word)
|
|
230
|
+
inner = word[1..-2]
|
|
231
|
+
result = +''
|
|
232
|
+
index = 0
|
|
233
|
+
|
|
234
|
+
while index < inner.length
|
|
235
|
+
if inner[index] == '\\' && index + 1 < inner.length
|
|
236
|
+
result << inner[index + 1]
|
|
237
|
+
index += 2
|
|
238
|
+
else
|
|
239
|
+
result << inner[index]
|
|
240
|
+
index += 1
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
result
|
|
245
|
+
end
|
|
246
|
+
|
|
122
247
|
def split_arguments(line)
|
|
123
248
|
args = []
|
|
124
249
|
current_arg = ""
|
|
@@ -129,7 +254,15 @@ module Poke
|
|
|
129
254
|
while i < line.length
|
|
130
255
|
char = line[i]
|
|
131
256
|
|
|
132
|
-
if !in_quotes && char.
|
|
257
|
+
if !in_quotes && char == '\\' && i + 1 < line.length
|
|
258
|
+
current_arg += char + line[i + 1]
|
|
259
|
+
i += 2
|
|
260
|
+
next
|
|
261
|
+
elsif in_quotes && quote_char == '"' && char == '\\' && i + 1 < line.length
|
|
262
|
+
current_arg += char + line[i + 1]
|
|
263
|
+
i += 2
|
|
264
|
+
next
|
|
265
|
+
elsif !in_quotes && char.match?(/\s/)
|
|
133
266
|
if !current_arg.empty?
|
|
134
267
|
args << current_arg
|
|
135
268
|
current_arg = ""
|
|
@@ -152,5 +285,73 @@ module Poke
|
|
|
152
285
|
args << current_arg unless current_arg.empty?
|
|
153
286
|
args
|
|
154
287
|
end
|
|
288
|
+
|
|
289
|
+
def expand_shell_word(word, variables)
|
|
290
|
+
result = +''
|
|
291
|
+
index = 0
|
|
292
|
+
quote = nil
|
|
293
|
+
|
|
294
|
+
while index < word.length
|
|
295
|
+
char = word[index]
|
|
296
|
+
|
|
297
|
+
if char == '\\' && quote != "'" && index + 1 < word.length
|
|
298
|
+
result << char << word[index + 1]
|
|
299
|
+
index += 2
|
|
300
|
+
next
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
if quote.nil? && (char == "'" || char == '"')
|
|
304
|
+
quote = char
|
|
305
|
+
result << char
|
|
306
|
+
index += 1
|
|
307
|
+
next
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
if quote == char
|
|
311
|
+
quote = nil
|
|
312
|
+
result << char
|
|
313
|
+
index += 1
|
|
314
|
+
next
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
if quote != "'" && char == '$'
|
|
318
|
+
name, consumed = read_variable(word, index)
|
|
319
|
+
if name && variables.key?(name)
|
|
320
|
+
result << substitute_value(variables[name].to_s, quote)
|
|
321
|
+
index += consumed
|
|
322
|
+
next
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
result << char
|
|
327
|
+
index += 1
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
result
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def read_variable(word, index)
|
|
334
|
+
suffix = word[index..]
|
|
335
|
+
if (match = suffix.match(/\A\$\{([A-Za-z_][A-Za-z0-9_]*)\}/))
|
|
336
|
+
[match[1], match[0].length]
|
|
337
|
+
elsif (match = suffix.match(/\A\$([A-Za-z_][A-Za-z0-9_]*)/))
|
|
338
|
+
[match[1], match[0].length]
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def substitute_value(value, quote)
|
|
343
|
+
return escape_double_quoted(value) if quote == '"'
|
|
344
|
+
return value if value.match?(UNQUOTED_SAFE)
|
|
345
|
+
|
|
346
|
+
"'#{value.gsub("'") { "'\\''" }}'"
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def escape_double_quoted(value)
|
|
350
|
+
value.gsub(/[\\$"`]/) { |char| "\\#{char}" }
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
UNQUOTED_SAFE = /\A[A-Za-z0-9_\-.,:@%+\/=]+\z/.freeze
|
|
354
|
+
JSON_BODY_FLAGS = %w[--data-ascii --data-binary --data-raw --data --json -d].freeze
|
|
355
|
+
private_constant :UNQUOTED_SAFE, :JSON_BODY_FLAGS
|
|
155
356
|
end
|
|
156
357
|
end
|
data/lib/poke/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: poke-your-api
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jan Bator
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: pastel
|
|
@@ -108,7 +107,6 @@ dependencies:
|
|
|
108
107
|
- - "~>"
|
|
109
108
|
- !ruby/object:Gem::Version
|
|
110
109
|
version: '0.12'
|
|
111
|
-
description:
|
|
112
110
|
email:
|
|
113
111
|
- jan.bator@gmail.com
|
|
114
112
|
executables:
|
|
@@ -146,7 +144,6 @@ licenses:
|
|
|
146
144
|
metadata:
|
|
147
145
|
homepage_uri: https://github.com/MrBananaLord/poke
|
|
148
146
|
source_code_uri: https://github.com/MrBananaLord/poke
|
|
149
|
-
post_install_message:
|
|
150
147
|
rdoc_options: []
|
|
151
148
|
require_paths:
|
|
152
149
|
- lib
|
|
@@ -161,8 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
161
158
|
- !ruby/object:Gem::Version
|
|
162
159
|
version: '0'
|
|
163
160
|
requirements: []
|
|
164
|
-
rubygems_version: 3.
|
|
165
|
-
signing_key:
|
|
161
|
+
rubygems_version: 3.6.9
|
|
166
162
|
specification_version: 4
|
|
167
163
|
summary: manage curl requests
|
|
168
164
|
test_files: []
|