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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -1
- data/README.md +177 -4
- data/completions/_jmespath +50 -0
- data/completions/jmespath.bash +178 -0
- data/docs/guides/compilation.md +310 -0
- data/docs/guides/completion.md +69 -0
- data/docs/guides/errors.md +200 -3
- data/docs/guides/functions.md +33 -0
- data/docs/guides/search.md +23 -0
- data/lib/jmespath/ast.rb +6 -1
- data/lib/jmespath/cli/argument_parser.rb +31 -0
- data/lib/jmespath/cli/arguments.rb +80 -0
- data/lib/jmespath/cli/failure_diagnostic.rb +1 -0
- data/lib/jmespath/cli/function_listing.rb +48 -0
- data/lib/jmespath/cli/help.rb +43 -0
- data/lib/jmespath/cli/interactive_session.rb +106 -0
- data/lib/jmespath/cli.rb +112 -16
- data/lib/jmespath/data_access.rb +12 -9
- data/lib/jmespath/diagnostic.rb +4 -3
- data/lib/jmespath/errors.rb +14 -0
- data/lib/jmespath/explanation.rb +95 -0
- data/lib/jmespath/expression.rb +93 -7
- data/lib/jmespath/failure_capture.rb +65 -0
- data/lib/jmespath/functions/coercions.rb +12 -5
- data/lib/jmespath/functions/conversion.rb +19 -1
- data/lib/jmespath/functions/function_call.rb +1 -1
- data/lib/jmespath/functions/json_value.rb +50 -0
- data/lib/jmespath/functions/references.rb +11 -10
- data/lib/jmespath/functions/signature.rb +6 -4
- data/lib/jmespath/functions.rb +12 -6
- data/lib/jmespath/input.rb +37 -0
- data/lib/jmespath/normalizer.rb +22 -5
- data/lib/jmespath/parser/projections.rb +5 -5
- data/lib/jmespath/parser.rb +2 -2
- data/lib/jmespath/plan.rb +17 -2
- data/lib/jmespath/search_result.rb +23 -0
- data/lib/jmespath/syntax_diagnostic.rb +32 -0
- data/lib/jmespath/tracing/collector.rb +109 -0
- data/lib/jmespath/tracing/evaluator.rb +113 -0
- data/lib/jmespath/tracing/field_lookup.rb +49 -0
- data/lib/jmespath/version.rb +1 -1
- data/lib/jmespath.rb +43 -8
- data/sig/jmespath.rbs +47 -3
- metadata +17 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5a6f19fa8b3debba295dd502232919a608226c50d486d849ff7148f07e5eeaea
|
|
4
|
+
data.tar.gz: 3a030e207e2645fa16c1511bc70f07b779d6cb53ca05ba320f51e83de5057dcc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|