jmespath-ruby 0.1.2 → 0.1.3

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -1
  3. data/README.md +177 -4
  4. data/completions/_jmespath +50 -0
  5. data/completions/jmespath.bash +178 -0
  6. data/docs/guides/compilation.md +310 -0
  7. data/docs/guides/completion.md +69 -0
  8. data/docs/guides/errors.md +200 -3
  9. data/docs/guides/functions.md +33 -0
  10. data/docs/guides/search.md +23 -0
  11. data/lib/jmespath/ast.rb +6 -1
  12. data/lib/jmespath/cli/argument_parser.rb +31 -0
  13. data/lib/jmespath/cli/arguments.rb +80 -0
  14. data/lib/jmespath/cli/failure_diagnostic.rb +1 -0
  15. data/lib/jmespath/cli/function_listing.rb +48 -0
  16. data/lib/jmespath/cli/help.rb +43 -0
  17. data/lib/jmespath/cli/interactive_session.rb +106 -0
  18. data/lib/jmespath/cli.rb +112 -16
  19. data/lib/jmespath/data_access.rb +12 -9
  20. data/lib/jmespath/diagnostic.rb +4 -3
  21. data/lib/jmespath/errors.rb +14 -0
  22. data/lib/jmespath/explanation.rb +95 -0
  23. data/lib/jmespath/expression.rb +93 -7
  24. data/lib/jmespath/failure_capture.rb +65 -0
  25. data/lib/jmespath/functions/coercions.rb +12 -5
  26. data/lib/jmespath/functions/conversion.rb +19 -1
  27. data/lib/jmespath/functions/function_call.rb +1 -1
  28. data/lib/jmespath/functions/json_value.rb +50 -0
  29. data/lib/jmespath/functions/references.rb +11 -10
  30. data/lib/jmespath/functions/signature.rb +6 -4
  31. data/lib/jmespath/functions.rb +12 -6
  32. data/lib/jmespath/input.rb +37 -0
  33. data/lib/jmespath/normalizer.rb +22 -5
  34. data/lib/jmespath/parser/projections.rb +5 -5
  35. data/lib/jmespath/parser.rb +2 -2
  36. data/lib/jmespath/plan.rb +17 -2
  37. data/lib/jmespath/search_result.rb +23 -0
  38. data/lib/jmespath/syntax_diagnostic.rb +32 -0
  39. data/lib/jmespath/tracing/collector.rb +109 -0
  40. data/lib/jmespath/tracing/evaluator.rb +113 -0
  41. data/lib/jmespath/tracing/field_lookup.rb +49 -0
  42. data/lib/jmespath/version.rb +1 -1
  43. data/lib/jmespath.rb +43 -8
  44. data/sig/jmespath.rbs +47 -3
  45. metadata +17 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f9f2db0a8d51af9e3258964210daf3aa1391f97370fca0d0e5610045aad9e012
4
- data.tar.gz: ec560bc1d5607e14175267d6b1bb82329a3d126686d99393c2cd6a8e7bc62585
3
+ metadata.gz: 5a6f19fa8b3debba295dd502232919a608226c50d486d849ff7148f07e5eeaea
4
+ data.tar.gz: 3a030e207e2645fa16c1511bc70f07b779d6cb53ca05ba320f51e83de5057dcc
5
5
  SHA512:
6
- metadata.gz: b8b8a4b5d663ae5b6ac54d093867c94ea420d836d44f1de5de1b781c21a984277a8211f7a6343392b335d0e451b7f3f749802e0ad910fc0af45d573fb305d2b9
7
- data.tar.gz: 985c5eddf2e47265eaa74f37afd4ea73094ae84f6a87ec90ec0c0501be1af03b3c46a4d95207be57d42ec47f4b94dc2b632a1e87b5eabfa712e3ba4232753794
6
+ metadata.gz: 8233ac05750fb3e6e91c637d7c4416d5ff47183b6c900f2a350340bf968058d2d7ee437aff69d10cc028929bf26b843e82e1fc94399ae5c2a1844f5335f81840
7
+ data.tar.gz: 54fc62c2faf79343c1ccfdcc2eaaadc29634c70ab4d29ebd5d6a2a7cdd5819a49a2c4a8a75af4b0b1954431bc0ed2a159a6991c08b55c2d289cb33efea976315
data/CHANGELOG.md CHANGED
@@ -5,6 +5,23 @@ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html) for t
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.1.3] - 2026-11-02
9
+
10
+ ### Added
11
+
12
+ - Add `JMESPath.validate` with immutable syntax diagnostics and configurable nesting limits.
13
+ - Add `--validate EXPRESSION` to both executables for syntax validation without reading standard input.
14
+ - Add `Expression#explain` with an immutable query tree, operation IDs, and source ranges.
15
+ - Add `Expression#trace` with bounded events for null fields and omitted projection items.
16
+ - Add `Expression#fetch` to require a non-null result and raise `NullResultError` when the result is null.
17
+ - Add `Expression#try_search` and `SearchResult` to return library-owned failures while preserving exceptions from application callbacks and conversions.
18
+ - Add `--file PATH` for JSON documents and `--query-file PATH` for UTF-8 query text.
19
+ - Add `--pretty` for indented JSON and `--raw-output` for unquoted string results.
20
+ - Add `--json-lines` to compile once and process independent JSON records incrementally.
21
+ - Add `--functions` to list built-in function signatures and descriptions without reading input.
22
+ - Add `--interactive --file PATH` to load one document and evaluate successive queries with recovery from query failures.
23
+ - Package manually installed Bash and Zsh completion for options and paths through both executable names.
24
+
8
25
  ## [0.1.2] - 2026-11-02
9
26
 
10
27
  ### Added
@@ -45,7 +62,8 @@ Initial implementation for Ruby 3.3 and later.
45
62
  The compatibility guide documents intentional corrections and limits.
46
63
  Applications that depend on the gem name `jmespath` must change that dependency explicitly.
47
64
 
48
- [unreleased]: https://github.com/svyatov/jmespath-ruby/compare/v0.1.2...HEAD
65
+ [unreleased]: https://github.com/svyatov/jmespath-ruby/compare/v0.1.3...HEAD
66
+ [0.1.3]: https://github.com/svyatov/jmespath-ruby/compare/v0.1.2...v0.1.3
49
67
  [0.1.2]: https://github.com/svyatov/jmespath-ruby/compare/v0.1.1...v0.1.2
50
68
  [0.1.1]: https://github.com/svyatov/jmespath-ruby/compare/v0.1.0...v0.1.1
51
69
  [0.1.0]: https://github.com/svyatov/jmespath-ruby/releases/tag/v0.1.0
data/README.md CHANGED
@@ -12,7 +12,7 @@ Search JSON and Ruby data with reusable queries and typed custom functions.
12
12
  In your Ruby project, add the gem with Bundler. Run `bundle init` first if the project has no Gemfile.
13
13
 
14
14
  ```sh
15
- bundle add jmespath-ruby --version "~> 0.1.2"
15
+ bundle add jmespath-ruby --version "~> 0.1.3"
16
16
  ```
17
17
 
18
18
  Save this Ruby example as `example.rb`:
@@ -76,7 +76,7 @@ Replace that Gemfile entry:
76
76
 
77
77
  ```diff
78
78
  -gem "jmespath"
79
- +gem "jmespath-ruby", "~> 0.1.2"
79
+ +gem "jmespath-ruby", "~> 0.1.3"
80
80
  ```
81
81
 
82
82
  Run `bundle install`. Your Ruby code keeps the same entry points:
@@ -94,6 +94,16 @@ See [compatibility and deliberate corrections](docs/guides/compatibility.md) bef
94
94
 
95
95
  ## Search
96
96
 
97
+ Use `Expression#fetch` when a Ruby caller requires a non-null result:
98
+
99
+ ```ruby
100
+ JMESPath.compile("user.name").fetch({user: {name: "Ada"}}) #=> "Ada"
101
+ ```
102
+
103
+ Null results raise `JMESPath::Errors::NullResultError`, whose `expression` attribute contains the query text.
104
+ False, zero, and empty values succeed.
105
+ See [required query results](docs/guides/compilation.md#required-results) for options and suppression behavior.
106
+
97
107
  Use `JMESPath.search` in Ruby code to evaluate a query:
98
108
 
99
109
  ```ruby
@@ -123,6 +133,25 @@ Compiled expressions are immutable and safe to share between threads.
123
133
  Each search uses separate evaluation state.
124
134
  Custom callbacks and input objects remain the caller's responsibility.
125
135
 
136
+ In Ruby code, inspect the query without evaluating input or resolving function names:
137
+
138
+ ```ruby
139
+ JMESPath.compile("user.name").explain[:root][:operation] #=> "subexpression"
140
+ ```
141
+
142
+ See [query inspection](docs/guides/compilation.md#query-inspection) for the immutable tree format, operation IDs, and source ranges.
143
+
144
+ In Ruby code, trace omissions during one evaluation with a bounded event limit:
145
+
146
+ ```ruby
147
+ query = JMESPath.compile("items[*].name")
148
+ report = query.trace({items: [{name: "Ada"}, {}, {name: false}]}, limit: 100)
149
+ report[:value] #=> ["Ada", false]
150
+ report[:events].map { |event| event[:type] } #=> ["field_null", "projection_omission"]
151
+ ```
152
+
153
+ See [evaluation tracing](docs/guides/compilation.md#evaluation-tracing) for event types, local item indexes, and truncation.
154
+
126
155
  In Ruby code, save evaluation options when compiling a query, then use `search` or its `call` alias:
127
156
 
128
157
  ```ruby
@@ -158,6 +187,22 @@ See [registry inspection](docs/guides/functions.md#registry-inspection) for all
158
187
 
159
188
  ## Errors and diagnostics
160
189
 
190
+ Use `Expression#try_search` in Ruby code to distinguish a successful null result from a library-owned failure:
191
+
192
+ ```ruby
193
+ query = JMESPath.compile("length(@)")
194
+ query.try_search("Ada").value #=> 3
195
+ query.try_search(4).success? #=> false
196
+ query.try_search(4).error.function_name #=> "length"
197
+ JMESPath.compile("missing").try_search({}).success? #=> true
198
+ ```
199
+
200
+ The frozen `JMESPath::SearchResult` exposes `success?`, `value`, and the original `error`.
201
+ Library-owned evaluation, JSON parsing, and native input I/O failures become failure results.
202
+ Invalid options and exceptions from application callbacks or conversions still raise.
203
+ Compilation can raise syntax errors before `try_search` runs.
204
+ See [failure results](docs/guides/errors.md#failure-results) for ownership and suppression rules.
205
+
161
206
  Format syntax failures in Ruby with `JMESPath::Diagnostic.format(error)` to get source coordinates, a query excerpt, and a caret.
162
207
  Function type and arity errors expose immutable validation data, including the function name, signature, argument counts or types, and available source ranges.
163
208
  Unknown-function errors expose the missing name and up to three suggestions from the active registry.
@@ -165,18 +210,146 @@ See [errors and diagnostics](docs/guides/errors.md) for examples, nullable field
165
210
 
166
211
  ## Command line
167
212
 
168
- Both `jmespath` and `jmespath.rb` accept an expression and a JSON document on standard input.
213
+ Both `jmespath` and `jmespath.rb` accept an expression and a JSON document from stdin or `--file PATH`.
214
+ Use `--query-file PATH` to read the expression from a UTF-8 file.
215
+ See [shell completion](docs/guides/completion.md) for manual Bash and Zsh setup for both executable names.
169
216
 
170
217
  ```sh
171
218
  printf '%s\n' '{"user":{"name":"Ada"}}' | jmespath 'user.name'
219
+ jmespath --file document.json 'user.name'
220
+ jmespath 'user.name' --file document.json
221
+ jmespath --file 'my document.json' 'user.name'
222
+ jmespath --file=--document.json 'user.name'
223
+ jmespath --file ./--document.json 'user.name'
224
+ jmespath --file - 'user.name'
225
+ jmespath --file document.json -- 'user.name'
226
+ jmespath --query-file query.jmespath < document.json
227
+ jmespath --query-file query.jmespath --file document.json
228
+ jmespath --pretty 'items' < document.json
229
+ jmespath --raw-output 'user.name' < document.json
230
+ ```
231
+
232
+ Document files are read as UTF-8 and closed after parsing, before query evaluation in single-document mode.
233
+ File input leaves stdin unused; omitting `--file` selects stdin.
234
+ Paths are literal: `--file -` reads a file named `-`.
235
+ Quote filenames with spaces; use the equals form or `./` prefix for option-like filenames.
236
+ Options can precede or follow the expression; `--` ends option parsing.
237
+ Supply exactly one query source: a positional expression or `--query-file PATH`.
238
+ Repeated file options, unknown options, missing values, and conflicting or absent query sources are usage failures.
239
+ Help and version flags must appear alone.
240
+
241
+ List built-in functions from the shell without reading stdin:
242
+
243
+ ```sh
244
+ jmespath --functions
172
245
  ```
173
246
 
174
- The result goes to standard output as JSON.
247
+ Each line shows a name, accepted argument types, and the description from public function metadata.
248
+ The listing is alphabetical and ends with a notation legend.
249
+ Unions use `|`, homogeneous arrays use `array<T>`, and expression references use `expref`.
250
+ A final `...` means the last argument repeats and remains required.
251
+ Runtime checks can be narrower than the declared types.
252
+ See [the function listing](docs/guides/functions.md#command-line-reference) for examples.
253
+
254
+ Use `--functions` alone; queries, paths, other modes, repeated flags, and values are usage failures.
255
+ The two-argument form `--validate --functions` retains literal query validation.
256
+ Listing exits with status 0 on success, 1 for output failures, or 2 for usage failures.
257
+ Usage failures leave stdout empty and print usage guidance on stderr.
258
+
259
+ Query files retain all source text, including trailing newlines and Unicode diagnostic coordinates.
260
+ An empty query file produces a syntax failure.
261
+ Query files close after reading, before document input is accessed.
262
+ Missing or unreadable query files leave document input untouched.
263
+ In single-document mode, execution parses JSON before compiling the expression.
264
+ Query paths follow the document path rules: `--query-file -` reads a literal file named `-`.
265
+
266
+ The result goes to standard output as compact JSON followed by a newline.
267
+ Use `--pretty` for JSON with two-space indentation and one final newline.
268
+ Both formats support objects, arrays, strings, numbers, booleans, and null, with Unicode preserved.
269
+ Pretty output works with positional or file queries and either document source.
270
+ Repeated `--pretty` options are usage failures.
271
+ Pretty formatting preserves stderr diagnostics, source coordinates, and exit statuses; failures before output starts leave stdout empty.
272
+ Use `--raw-output` to print string results without JSON quotes or escape encoding.
273
+ Other result types retain compact JSON encoding.
274
+ Raw output appends one newline and preserves every embedded and trailing newline in the result.
275
+ An empty string produces one newline; a string ending with one newline produces two.
276
+ Repeated `--raw-output` options and combinations with `--pretty` are usage failures.
277
+ Raw output preserves stderr diagnostics, source coordinates, and exit statuses; failures before output starts leave stdout empty.
175
278
  Syntax, function type, and arity failures include source coordinates, a query excerpt, and a caret when available.
176
279
  Unknown functions suggest similar registered names.
177
280
  Malformed JSON input reports `Invalid JSON input` without including document fragments.
178
281
  These failures go to standard error and exit with status 1.
179
282
  Usage failures exit with status 2; `--help` and `--version` exit with status 0 without reading input.
283
+
284
+ Process independent JSON records with these shell commands:
285
+
286
+ ```sh
287
+ jmespath --json-lines 'user.name' < events.jsonl
288
+ jmespath --json-lines --file events.jsonl --query-file query.jmespath
289
+ ```
290
+
291
+ JSON Lines mode compiles the query once before opening document input or reading stdin.
292
+ Each physical line must contain one complete JSON value; blank and whitespace-only lines fail.
293
+ LF, CRLF, and a final record without a newline are accepted.
294
+ Each result is compact JSON followed by a newline, including `null` and `false`.
295
+ Empty input succeeds without output when the query is valid; an invalid query still fails.
296
+
297
+ Processing stops at the first failure with status 1 and an `Input line N:` diagnostic prefix.
298
+ Earlier results remain on stdout; check the exit status before treating output as complete.
299
+ Query compilation and file-open errors have no input line prefix.
300
+ Memory is proportional to the current record, its evaluation, and its serialized result, plus the compiled query.
301
+ Output uses normal buffering.
302
+ Owned files close after processing; caller-owned streams remain open.
303
+ Injected `CLI.run` input needs `gets` for JSON Lines or `read` for document mode; output needs only `puts`.
304
+ Repeated `--json-lines` flags and combinations with `--pretty`, `--raw-output`, or validation are usage failures.
305
+
306
+ Start a session against one loaded document:
307
+
308
+ ```sh
309
+ jmespath --interactive --file document.json
310
+ ```
311
+
312
+ Enter one UTF-8 query per line; empty lines and lines containing only spaces or tabs are ignored.
313
+ Use `:help` for session instructions and `:quit` to finish, or end input with EOF.
314
+ Queries accept LF, CRLF, and a final line without a newline.
315
+ Each successful query prints compact JSON and a final newline to stdout, then flushes when the stream supports it.
316
+ Prompts appear only when stdin is a terminal; prompts, help, and diagnostics use stderr.
317
+ The document loads once and its file closes before the first prompt or command read.
318
+
319
+ Queries can also come from a pipe without prompts:
320
+
321
+ ```sh
322
+ printf 'user.name\nlength(user.name)\n' | jmespath --interactive --file document.json
323
+ ```
324
+
325
+ Query errors, unknown commands, and invalid UTF-8 query lines produce diagnostics and allow the session to continue.
326
+ Failed queries produce no JSON result; successful results remain available.
327
+ EOF and `:quit` return status 0 even after query failures.
328
+ Document and stream failures terminate with status 1; usage failures return status 2.
329
+ Interactive mode requires `--file PATH` and rejects positional queries, `--query-file`, other modes, information flags, and repeated flags.
330
+ Readers supplied to `CLI.run` need `gets`; `tty?` is optional and absent detection means no prompts.
331
+ Writers need `puts`; `flush` is optional except for terminal prompts, whose diagnostic stream needs both `print` and `flush`.
332
+ Caller-owned streams remain open; history, completion, multiline editing, and document reloads are unavailable.
333
+
334
+ Validate syntax without providing a JSON document by running this shell command:
335
+
336
+ ```sh
337
+ jmespath --validate 'items[*].name'
338
+ jmespath --validate --query-file query.jmespath
339
+ jmespath --query-file query.jmespath --validate
340
+ ```
341
+
342
+ Both executables support `--validate EXPRESSION` without reading standard input.
343
+ File validation also leaves stdin untouched and rejects document options such as `--file`.
344
+ Combining `--pretty` with validation is a usage failure, rejected before opening input files or reading stdin.
345
+ Combining `--raw-output` with validation follows the same rule.
346
+ The exact two-argument form `--validate EXPRESSION` always treats the second argument as query text, including flag-like text.
347
+ Thus `jmespath --validate --pretty` validates the literal expression `--pretty`.
348
+ Likewise, `jmespath --validate --raw-output` validates the literal expression `--raw-output`.
349
+ Valid syntax produces no output and exits with status 0.
350
+ Query failures print a diagnostic to standard error and exit with status 1; incorrect usage exits with status 2.
351
+ Validation does not check function availability or runtime argument types.
352
+ The Ruby interface is `JMESPath.validate(expression, max_depth: 128)`.
180
353
  See [CLI diagnostics](docs/guides/errors.md#cli-diagnostics) for examples and fallback behavior.
181
354
 
182
355
  ## Guides
@@ -0,0 +1,50 @@
1
+ #compdef jmespath jmespath.rb
2
+ local index expecting_path=0 literal_path=0 value raw option candidate suffix
3
+ local -a paths
4
+ for ((index = 2; index < CURRENT; index++)); do
5
+ if ((expecting_path)); then expecting_path=0; continue; fi
6
+ case ${(Q)words[index]} in
7
+ --file|--query-file) expecting_path=1 ;;
8
+ --) return ;;
9
+ esac
10
+ done
11
+ option=${(Q)${PREFIX%%=*}}
12
+ if ((expecting_path)); then
13
+ if [[ $compstate[quoting] == dollars ]]; then
14
+ raw=$words[CURRENT]
15
+ value=${(Q)raw}
16
+ [[ $value == "$raw" ]] && value=${(Q)${:-"$raw'"}}
17
+ literal_path=1
18
+ else
19
+ _files
20
+ fi
21
+ elif [[ $option == --file || $option == --query-file ]]; then
22
+ compset -P "${PREFIX%%=*}="
23
+ raw=${words[CURRENT]#*=}
24
+ if [[ $raw == \$\'* ]]; then
25
+ value=${(Q)raw}
26
+ [[ $value == "$raw" ]] && value=${(Q)${:-"$raw'"}}
27
+ literal_path=1
28
+ elif [[ $PREFIX == *\$\'* || $raw == \'* || $raw == '"~'* || $raw == '\~'* ]]; then
29
+ value=${(Q)PREFIX}
30
+ literal_path=1
31
+ elif [[ $compstate[quoting] == single || $compstate[quoting] == double ]]; then
32
+ _files -S ''
33
+ else
34
+ _files
35
+ fi
36
+ elif [[ $PREFIX == -* ]]; then
37
+ compadd -- -h --help --version --functions --file --query-file \
38
+ --validate --pretty --raw-output --json-lines --interactive
39
+ fi
40
+
41
+ if ((literal_path)); then
42
+ paths=( "$value"*(NM) )
43
+ for candidate in "${paths[@]}"; do
44
+ suffix=
45
+ if [[ $compstate[quoting] == dollars && -z $QISUFFIX && ! -d $candidate ]]; then
46
+ suffix="'"
47
+ fi
48
+ compadd -U -i "$IPREFIX" -S "$suffix" -f -- "$candidate"
49
+ done
50
+ fi
@@ -0,0 +1,178 @@
1
+ # Bash 3.2 completion for both executable names. Source this file to register it.
2
+ # Rejoin Readline word-break fragments only when they are adjacent in the input.
3
+ _jmespath_completion_words() {
4
+ local remaining=${COMP_LINE:0:COMP_POINT} piece joined= index
5
+ for ((index = COMP_CWORD; index >= 0; index--)); do
6
+ piece=${COMP_WORDS[index]}
7
+ if ((index == COMP_CWORD)); then
8
+ while [[ $remaining != *"$piece" ]]; do piece=${piece%?}; done
9
+ fi
10
+ joined=$piece$joined
11
+ remaining=${remaining%"$piece"}
12
+ if ((index == 0)) || [[ $remaining == *[[:space:]] ]]; then
13
+ words=("$joined" "${words[@]}")
14
+ joined=
15
+ while [[ $remaining == *[[:space:]] ]]; do
16
+ remaining=${remaining%?}
17
+ done
18
+ fi
19
+ done
20
+ }
21
+
22
+ # Decode quoting and HOME references without evaluating filename text.
23
+ _jmespath_completion_unquote() {
24
+ local text=$1 character next quote= escape decoded digits skip_ansi=0
25
+ REPLY=
26
+ while [[ -n $text ]]; do
27
+ character=${text:0:1}
28
+ text=${text:1}
29
+ if [[ $quote == ansi ]]; then
30
+ if [[ $character == "'" ]]; then
31
+ quote=
32
+ elif [[ $character == \\ ]]; then
33
+ next=${text:0:1}
34
+ text=${text:1}
35
+ ((skip_ansi)) && continue
36
+ escape=\\$next
37
+ case $next in
38
+ [0-7])
39
+ digits=$next
40
+ while ((${#digits} < 3)) && [[ $text == [0-7]* ]]; do
41
+ digits+=${text:0:1}; text=${text:1}
42
+ done
43
+ escape=\\0$digits ;;
44
+ x)
45
+ digits=
46
+ while ((${#digits} < 2)) && [[ $text == [[:xdigit:]]* ]]; do
47
+ digits+=${text:0:1}; text=${text:1}
48
+ done
49
+ if [[ -z $digits ]]; then REPLY+='\x'; continue; fi
50
+ escape=\\x$digits ;;
51
+ c)
52
+ next=${text:0:1}; text=${text:1}
53
+ printf -v digits '%d' "'$next"
54
+ printf -v escape '\\%03o' "$((digits & 31))" ;;
55
+ "'"|'"'|'?') escape=$next ;;
56
+ esac
57
+ printf -v decoded '%b' "$escape"
58
+ REPLY+=$decoded
59
+ [[ -z $decoded ]] && skip_ansi=1
60
+ elif ((!skip_ansi)); then
61
+ REPLY+=$character
62
+ fi
63
+ elif [[ $quote == "'" ]]; then
64
+ if [[ $character == "'" ]]; then quote=; else REPLY+=$character; fi
65
+ elif [[ $character == \\ ]]; then
66
+ next=${text:0:1}
67
+ if [[ $quote == '"' && $next != [\$\`\"\\] && $next != $'\n' ]]; then
68
+ REPLY+=$character
69
+ else
70
+ text=${text:1}
71
+ [[ $next != $'\n' ]] && REPLY+=$next
72
+ fi
73
+ elif [[ $character == '$' && -z $quote && $text == "'"* ]]; then
74
+ quote=ansi
75
+ skip_ansi=0
76
+ text=${text:1}
77
+ elif [[ $character == '$' && ( $text == HOME || $text == HOME[/\"]* ) ]]; then
78
+ REPLY+=$HOME
79
+ text=${text#HOME}
80
+ elif [[ $character == '$' && $text == '{HOME}'* ]]; then
81
+ REPLY+=$HOME
82
+ text=${text#'{HOME}'}
83
+ elif [[ $character == "'" || $character == '"' ]]; then
84
+ if [[ $quote == "$character" ]]; then
85
+ quote=
86
+ elif [[ -z $quote ]]; then
87
+ quote=$character
88
+ else
89
+ REPLY+=$character
90
+ fi
91
+ else
92
+ REPLY+=$character
93
+ fi
94
+ done
95
+ unclosed_quote=$quote
96
+ }
97
+
98
+ _jmespath_completion() {
99
+ local -a words=()
100
+ local current word candidate prefix REPLY unclosed_quote raw_path option=
101
+ local index expecting_path=0 expand_home=0
102
+ _jmespath_completion_words
103
+ current=${words[${#words[@]}-1]}
104
+ COMPREPLY=()
105
+
106
+ for ((index = 1; index < ${#words[@]} - 1; index++)); do
107
+ _jmespath_completion_unquote "${words[index]}"
108
+ word=$REPLY
109
+ if ((expecting_path)); then
110
+ expecting_path=0
111
+ continue
112
+ fi
113
+ case $word in
114
+ --file|--query-file) expecting_path=1 ;;
115
+ --) return ;;
116
+ esac
117
+ done
118
+
119
+ raw_path=$current
120
+ if ((!expecting_path)); then
121
+ if [[ $current == *=* ]]; then
122
+ _jmespath_completion_unquote "${current%%=*}"
123
+ case $REPLY in
124
+ --file|--query-file)
125
+ expecting_path=1
126
+ option=$REPLY=
127
+ raw_path=${current#*=}
128
+ [[ -n $unclosed_quote ]] && raw_path= ;;
129
+ esac
130
+ fi
131
+ fi
132
+
133
+ if ((expecting_path)); then
134
+ case $raw_path in
135
+ '~'|'~/'*) expand_home=1 ;;
136
+ '~'*) return ;;
137
+ esac
138
+ # Readline replaces only the suffix after its last unquoted word break.
139
+ _jmespath_completion_unquote "${current%"${2-}"}"
140
+ prefix=$REPLY
141
+ _jmespath_completion_unquote "$current"
142
+ current=$REPLY
143
+ if [[ -n $option ]]; then
144
+ current=${current#"$option"}
145
+ if [[ $prefix == "$option"* ]]; then
146
+ prefix=${prefix#"$option"}
147
+ option=
148
+ fi
149
+ fi
150
+ if ((expand_home)); then
151
+ current=$HOME${current#\~}
152
+ [[ $prefix == '~'* ]] && prefix=$HOME${prefix#\~}
153
+ elif [[ $current == '~'* ]]; then
154
+ # A quoted or escaped tilde must stay literal when Readline rewrites it.
155
+ current=./$current
156
+ [[ -n $prefix ]] && prefix=./$prefix
157
+ fi
158
+ while IFS= read -r -d '' candidate; do
159
+ COMPREPLY[${#COMPREPLY[@]}]=$option${candidate#"$prefix"}
160
+ done < <(
161
+ shopt -s nullglob
162
+ shopt -u failglob
163
+ for candidate in "$current"*; do printf '%s\0' "$candidate"; done
164
+ )
165
+ # Enable Readline filename quoting only for paths, including on Bash 3.2.
166
+ if type compopt >/dev/null 2>&1; then
167
+ compopt -o filenames
168
+ else
169
+ compgen -f -- "$current" >/dev/null || :
170
+ fi
171
+ elif [[ $current == -* ]]; then
172
+ while IFS= read -r candidate; do
173
+ COMPREPLY[${#COMPREPLY[@]}]=$candidate
174
+ done < <(compgen -W '-h --help --version --functions --file --query-file --validate --pretty --raw-output --json-lines --interactive' -- "$current")
175
+ fi
176
+ }
177
+
178
+ complete -F _jmespath_completion jmespath jmespath.rb