New Upstream Release - gojq
Ready changes
Summary
Merged new upstream version: 0.12.13 (was: 0.12.11).
Diff
diff --git a/.dockerignore b/.dockerignore
index c8e02dc..ac00163 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -6,4 +6,12 @@
*.exe
*.test
*.out
-/.github/
+*.md
+*.y
+**/*.jq
+**/*.json
+**/*.yaml
+**/*_test.go
+.github
+_gojq
+_tools
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index edbfe86..8ed1668 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -6,6 +6,9 @@ on:
- main
pull_request:
+permissions:
+ contents: read
+
jobs:
test:
name: Test
@@ -13,12 +16,12 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
- go: [1.19.x, 1.18.x, 1.17.x]
+ go: [1.20.x, 1.19.x, 1.18.x]
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}
- name: Test
@@ -28,6 +31,7 @@ jobs:
if: matrix.os != 'macos-latest'
- name: Lint
run: make lint
+ if: matrix.go >= '1.19.x'
- name: Check tools
run: make check-tools
- name: Check go generate
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index f9e090b..19f75ad 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -5,38 +5,36 @@ on:
tags:
- 'v*'
-jobs:
+permissions:
+ contents: write
+ packages: write
+jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
-
- name: Checkout code
uses: actions/checkout@v3
-
- name: Setup Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v4
with:
go-version: 1.x
-
- name: Cross build
run: make cross
-
- name: Create Release
- id: create_release
- uses: actions/create-release@v1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ uses: ncipollo/release-action@v1
with:
- tag_name: ${{ github.ref }}
- release_name: Release ${{ github.ref }}
-
- - name: Upload
- run: make upload
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ name: Release ${{ github.ref_name }}
+ artifacts: 'goxz/*'
+ docker:
+ name: Docker
+ runs-on: ubuntu-latest
+ needs: release
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
- name: Docker metadata
uses: docker/metadata-action@v4
id: metadata
@@ -48,28 +46,23 @@ jobs:
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
-
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
-
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
-
- name: Build and release Docker image
- uses: docker/build-push-action@v3
+ uses: docker/build-push-action@v4
with:
context: .
push: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fa03401..8477cd3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,16 @@
# Changelog
+## [v0.12.13](https://github.com/itchyny/gojq/compare/v0.12.12..v0.12.13) (2023-06-01)
+* implement `@urid` format string to decode URI values
+* fix functions returning arrays not to emit nil slices (`flatten`, `group_by`,
+ `unique`, `unique_by`, `nth`, `indices`, `path`, and `modulemeta.deps`)
+
+## [v0.12.12](https://github.com/itchyny/gojq/compare/v0.12.11..v0.12.12) (2023-03-01)
+* fix assignment operator (`=`) with overlapping paths and multiple values (`[[]] | .. = ..`)
+* fix crash on multiplying large numbers to an empty string (`9223372036854775807 * ""`)
+* improve zsh completion file
+
## [v0.12.11](https://github.com/itchyny/gojq/compare/v0.12.10..v0.12.11) (2022-12-24)
-* fix crash on assignment operators (`=`) with multiple values (`. = (0,0)`)
+* fix crash on assignment operator (`=`) with multiple values (`. = (0,0)`)
* fix `isnormal` and `normals` functions against subnormal numbers
## [v0.12.10](https://github.com/itchyny/gojq/compare/v0.12.9..v0.12.10) (2022-12-01)
@@ -229,7 +239,7 @@
## [v0.7.0](https://github.com/itchyny/gojq/compare/v0.6.0..v0.7.0) (2019-12-22)
* implement YAML input (`--yaml-input`) and output (`--yaml-output`)
* fix pipe in object value
-* fix precedence of if, try, reduce and foreach expressions
+* fix precedence of `if`, `try`, `reduce` and `foreach` expressions
* release from GitHub Actions
## [v0.6.0](https://github.com/itchyny/gojq/compare/v0.5.0..v0.6.0) (2019-08-26)
diff --git a/Dockerfile b/Dockerfile
index 284ece7..51f8632 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.19 AS builder
+FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
diff --git a/LICENSE b/LICENSE
index e3fc027..3f4fcb2 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2019-2022 itchyny
+Copyright (c) 2019-2023 itchyny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile b/Makefile
index 983f994..b7cdb40 100644
--- a/Makefile
+++ b/Makefile
@@ -101,10 +101,3 @@ bump: $(GOBIN)/gobump
git commit -am "bump up version to $(VERSION)"
git tag "v$(VERSION)"
git push --atomic origin main tag "v$(VERSION)"
-
-.PHONY: upload
-upload: $(GOBIN)/ghr
- ghr "v$(VERSION)" goxz
-
-$(GOBIN)/ghr:
- go install github.com/tcnksm/ghr@latest
diff --git a/README.md b/README.md
index 29888a9..ca13b2f 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[![release](https://img.shields.io/github/release/itchyny/gojq/all.svg)](https://github.com/itchyny/gojq/releases)
[![pkg.go.dev](https://pkg.go.dev/badge/github.com/itchyny/gojq)](https://pkg.go.dev/github.com/itchyny/gojq)
-### Pure Go implementation of [jq](https://github.com/stedolan/jq)
+### Pure Go implementation of [jq](https://github.com/jqlang/jq)
This is an implementation of jq command written in Go language.
You can also embed gojq as a library to your Go products.
@@ -77,10 +77,10 @@ docker run -i --rm ghcr.io/itchyny/gojq
- gojq implements nice error messages for invalid query and JSON input. The error message of jq is sometimes difficult to tell where to fix the query.
- gojq does not keep the order of object keys. I understand this might cause problems for some scripts but basically, we should not rely on the order of object keys. Due to this limitation, gojq does not have `keys_unsorted` function and `--sort-keys` (`-S`) option. I would implement when ordered map is implemented in the standard library of Go but I'm less motivated.
- gojq supports arbitrary-precision integer calculation while jq does not; jq loses the precision of large integers when calculation is involved. Note that even with gojq, all mathematical functions, including `floor` and `round`, convert integers to floating-point numbers; only addition, subtraction, multiplication, modulo, and division operators (when divisible) keep the integer precision. To calculate floor division of integers without losing the precision, use `def idivide($n): (. - . % $n) / $n;`. To round down floating-point numbers to integers, use `def ifloor: floor | tostring | tonumber;`, but note that this function does not work with large floating-point numbers and also loses the precision of large integers.
-- gojq fixes various bugs of jq. gojq correctly deletes elements of arrays by `|= empty` ([jq#2051](https://github.com/stedolan/jq/issues/2051)). gojq fixes `try`/`catch` handling ([jq#1859](https://github.com/stedolan/jq/issues/1859), [jq#1885](https://github.com/stedolan/jq/issues/1885), [jq#2140](https://github.com/stedolan/jq/issues/2140)). gojq fixes `nth/2` to output nothing when the count is equal to or larger than the stream size ([jq#1867](https://github.com/stedolan/jq/issues/1867)). gojq consistently counts by characters (not by bytes) in `index`, `rindex`, and `indices` functions; `"12345" | .[index("3"):]` results in `"345"` ([jq#1430](https://github.com/stedolan/jq/issues/1430), [jq#1624](https://github.com/stedolan/jq/issues/1624)). gojq handles overlapping occurrence differently in `rindex` and `indices`; `"ababa" | [rindex("aba"), indices("aba")]` results in `[2,[0,2]]` ([jq#2433](https://github.com/stedolan/jq/issues/2433)). gojq supports string indexing; `"abcde"[2]` ([jq#1520](https://github.com/stedolan/jq/issues/1520)). gojq accepts indexing query `.e0` ([jq#1526](https://github.com/stedolan/jq/issues/1526), [jq#1651](https://github.com/stedolan/jq/issues/1651)), and allows `gsub` to handle patterns including `"^"` ([jq#2148](https://github.com/stedolan/jq/issues/2148)). gojq improves variable lexer to allow using keywords for variable names, especially in binding patterns, also disallows spaces after `$` ([jq#526](https://github.com/stedolan/jq/issues/526)). gojq fixes handling files with no newline characters at the end ([jq#2374](https://github.com/stedolan/jq/issues/2374)).
-- gojq truncates down floating-point numbers on indexing (`[0] | .[0.5]` results in `0` not `null`), and slicing (`[0,1,2] | .[0.5:1.5]` results in `[0]` not `[0,1]`). gojq parses unary operators with higher precedence than variable binding (`[-1 as $x | 1,$x]` results in `[1,-1]` not `[-1,-1]`). gojq implements `@uri` to escape all the reserved characters defined in RFC 3986, Sec. 2.2 ([jq#1506](https://github.com/stedolan/jq/issues/1506)), and fixes `@base64d` to allow binary string as the decoded string ([jq#1931](https://github.com/stedolan/jq/issues/1931)). gojq improves time formatting and parsing; deals with `%f` in `strftime` and `strptime` ([jq#1409](https://github.com/stedolan/jq/issues/1409)), parses timezone offsets with `fromdate` and `fromdateiso8601` ([jq#1053](https://github.com/stedolan/jq/issues/1053)), supports timezone name/offset with `%Z`/`%z` in `strptime` ([jq#929](https://github.com/stedolan/jq/issues/929), [jq#2195](https://github.com/stedolan/jq/issues/2195)), and looks up correct timezone during daylight saving time on formatting with `%Z` ([jq#1912](https://github.com/stedolan/jq/issues/1912)). gojq supports nanoseconds in date and time functions.
-- gojq does not support some functions intentionally; `get_jq_origin`, `get_prog_origin`, `get_search_list` (unstable, not listed in jq document), `input_line_number`, `$__loc__` (performance issue), `recurse_down` (deprecated in jq). gojq does not support some flags; `--ascii-output, -a` (performance issue), `--seq` (not used commonly), `--sort-keys, -S` (sorts by default because `map[string]interface{}` does not keep the order), `--unbuffered` (unbuffered by default). gojq does not parse JSON extensions supported by jq; `NaN`, `Infinity`, and `[000]`. gojq normalizes floating-point numbers to fit to double-precision floating-point numbers. gojq does not support some regular expression flags (regular expression engine differences). gojq does not support BOM (`encoding/json` does not support this). gojq disallows using keywords for function names (`def true: .; true` is a confusing query), and module name prefixes in function declarations (using module prefixes like `def m::f: .;` is undocumented).
-- gojq supports reading from YAML input (`--yaml-input`) while jq does not. gojq also supports YAML output (`--yaml-output`).
+- gojq fixes various bugs of jq. gojq correctly deletes elements of arrays by `|= empty` ([jq#2051](https://github.com/jqlang/jq/issues/2051)). gojq fixes `try`/`catch` handling ([jq#1859](https://github.com/jqlang/jq/issues/1859), [jq#1885](https://github.com/jqlang/jq/issues/1885), [jq#2140](https://github.com/jqlang/jq/issues/2140)). gojq fixes `nth/2` to output nothing when the count is equal to or larger than the stream size ([jq#1867](https://github.com/jqlang/jq/issues/1867)). gojq consistently counts by characters (not by bytes) in `index`, `rindex`, and `indices` functions; `"12345" | .[index("3"):]` results in `"345"` ([jq#1430](https://github.com/jqlang/jq/issues/1430), [jq#1624](https://github.com/jqlang/jq/issues/1624)). gojq handles overlapping occurrence differently in `rindex` and `indices`; `"ababa" | [rindex("aba"), indices("aba")]` results in `[2,[0,2]]` ([jq#2433](https://github.com/jqlang/jq/issues/2433)). gojq supports string indexing; `"abcde"[2]` ([jq#1520](https://github.com/jqlang/jq/issues/1520)). gojq accepts indexing query `.e0` ([jq#1526](https://github.com/jqlang/jq/issues/1526), [jq#1651](https://github.com/jqlang/jq/issues/1651)), and allows `gsub` to handle patterns including `"^"` ([jq#2148](https://github.com/jqlang/jq/issues/2148)). gojq improves variable lexer to allow using keywords for variable names, especially in binding patterns, also disallows spaces after `$` ([jq#526](https://github.com/jqlang/jq/issues/526)). gojq fixes handling files with no newline characters at the end ([jq#2374](https://github.com/jqlang/jq/issues/2374)).
+- gojq truncates down floating-point numbers on indexing (`[0] | .[0.5]` results in `0` not `null`), and slicing (`[0,1,2] | .[0.5:1.5]` results in `[0]` not `[0,1]`). gojq parses unary operators with higher precedence than variable binding (`[-1 as $x | 1,$x]` results in `[1,-1]` not `[-1,-1]`). gojq implements `@uri` to escape all the reserved characters defined in RFC 3986, Sec. 2.2 ([jq#1506](https://github.com/jqlang/jq/issues/1506)), and fixes `@base64d` to allow binary string as the decoded string ([jq#1931](https://github.com/jqlang/jq/issues/1931)). gojq improves time formatting and parsing; deals with `%f` in `strftime` and `strptime` ([jq#1409](https://github.com/jqlang/jq/issues/1409)), parses timezone offsets with `fromdate` and `fromdateiso8601` ([jq#1053](https://github.com/jqlang/jq/issues/1053)), supports timezone name/offset with `%Z`/`%z` in `strptime` ([jq#929](https://github.com/jqlang/jq/issues/929), [jq#2195](https://github.com/jqlang/jq/issues/2195)), and looks up correct timezone during daylight saving time on formatting with `%Z` ([jq#1912](https://github.com/jqlang/jq/issues/1912)). gojq supports nanoseconds in date and time functions.
+- gojq does not support some functions intentionally; `get_jq_origin`, `get_prog_origin`, `get_search_list` (unstable, not listed in jq document), `input_line_number`, `$__loc__` (performance issue), `recurse_down` (deprecated in jq). gojq does not support some flags; `--ascii-output, -a` (performance issue), `--seq` (not used commonly), `--sort-keys, -S` (sorts by default because `map[string]any` does not keep the order), `--unbuffered` (unbuffered by default). gojq does not parse JSON extensions supported by jq; `NaN`, `Infinity`, and `[000]`. gojq normalizes floating-point numbers to fit to double-precision floating-point numbers. gojq does not support or behaves differently with some regular expression metacharacters and flags (regular expression engine differences). gojq does not support BOM (`encoding/json` does not support this). gojq disallows using keywords for function names (`def true: .; true` is a confusing query), and module name prefixes in function declarations (using module prefixes like `def m::f: .;` is undocumented).
+- gojq supports reading from YAML input (`--yaml-input`) while jq does not. gojq also supports YAML output (`--yaml-output`). gojq supports a few filters missing in jq; `scan/2` ([jq#2207](https://github.com/jqlang/jq/pull/2207)), and `@urid` format string ([jq#2261](https://github.com/jqlang/jq/issues/2261)).
### Color configuration
The gojq command automatically disables coloring output when the output is not a tty.
@@ -109,7 +109,7 @@ func main() {
if err != nil {
log.Fatalln(err)
}
- input := map[string]interface{}{"foo": []interface{}{1, 2, 3}}
+ input := map[string]any{"foo": []any{1, 2, 3}}
iter := query.Run(input) // or query.RunWithContext
for {
v, ok := iter.Next()
@@ -128,9 +128,9 @@ func main() {
- Secondly, get the result iterator
- using [`query.Run`](https://pkg.go.dev/github.com/itchyny/gojq#Query.Run) or [`query.RunWithContext`](https://pkg.go.dev/github.com/itchyny/gojq#Query.RunWithContext)
- or alternatively, compile the query using [`gojq.Compile`](https://pkg.go.dev/github.com/itchyny/gojq#Compile) and then [`code.Run`](https://pkg.go.dev/github.com/itchyny/gojq#Code.Run) or [`code.RunWithContext`](https://pkg.go.dev/github.com/itchyny/gojq#Code.RunWithContext). You can reuse the `*Code` against multiple inputs to avoid compilation of the same query. But for arguments of `code.Run`, do not give values sharing same data between multiple calls.
- - In either case, you cannot use custom type values as the query input. The type should be `[]interface{}` for an array and `map[string]interface{}` for a map (just like decoded to an `interface{}` using the [encoding/json](https://golang.org/pkg/encoding/json/) package). You can't use `[]int` or `map[string]string`, for example. If you want to query your custom struct, marshal to JSON, unmarshal to `interface{}` and use it as the query input.
-- Thirdly, iterate through the results using [`iter.Next() (interface{}, bool)`](https://pkg.go.dev/github.com/itchyny/gojq#Iter). The iterator can emit an error so make sure to handle it. The method returns `true` with results, and `false` when the iterator terminates.
- - The return type is not `(interface{}, error)` because iterators can emit multiple errors and you can continue after an error. It is difficult for the iterator to tell the termination in this situation.
+ - In either case, you cannot use custom type values as the query input. The type should be `[]any` for an array and `map[string]any` for a map (just like decoded to an `any` using the [encoding/json](https://golang.org/pkg/encoding/json/) package). You can't use `[]int` or `map[string]string`, for example. If you want to query your custom struct, marshal to JSON, unmarshal to `any` and use it as the query input.
+- Thirdly, iterate through the results using [`iter.Next() (any, bool)`](https://pkg.go.dev/github.com/itchyny/gojq#Iter). The iterator can emit an error so make sure to handle it. The method returns `true` with results, and `false` when the iterator terminates.
+ - The return type is not `(any, error)` because iterators can emit multiple errors and you can continue after an error. It is difficult for the iterator to tell the termination in this situation.
- Note that the result iterator may emit infinite number of values; `repeat(0)` and `range(infinite)`. It may stuck with no output value; `def f: f; f`. Use `RunWithContext` when you want to limit the execution time.
[`gojq.Compile`](https://pkg.go.dev/github.com/itchyny/gojq#Compile) allows to configure the following compiler options.
diff --git a/_gojq b/_gojq
index 4c94718..d403a31 100644
--- a/_gojq
+++ b/_gojq
@@ -2,31 +2,42 @@
_gojq()
{
- _arguments -C \
- '(-c --compact-output)'{-c,--compact-output}'[compact output]' \
- '(-r --raw-output)'{-r,--raw-output}'[output raw strings]' \
- '(-j --join-output)'{-j,--join-output}'[stop printing a newline after each output]' \
- '(-0 --nul-output)'{-0,--nul-output}'[print NUL after each output]' \
- '(-C --color-output)'{-C,--color-output}'[colorize output even if piped]' \
- '(-M --monochrome-output)'{-M,--monochrome-output}'[stop colorizing output]' \
- '(--yaml-output)'--yaml-output'[output by YAML]' \
- '(--indent)'--indent'[number of spaces for indentation]:indentation count' \
- '(--tab)'--tab'[use tabs for indentation]' \
+ _arguments -s -S \
+ '(-r --raw-output -j --join-output -0 --nul-output)'{-r,--raw-output}'[output raw strings]' \
+ '(-r --raw-output -j --join-output -0 --nul-output)'{-j,--join-output}'[output without newlines]' \
+ '(-r --raw-output -j --join-output -0 --nul-output)'{-0,--nul-output}'[output with NUL character]' \
+ '(-c --compact-output --indent --tab --yaml-output)'{-c,--compact-output}'[output without pretty-printing]' \
+ '(-c --compact-output --tab --yaml-output)--indent=[number of spaces for indentation]:indentation count:(2 4 8)' \
+ '(-c --compact-output --indent --yaml-output)--tab[use tabs for indentation]' \
+ '(-c --compact-output --indent --tab )--yaml-output[output in YAML format]' \
+ '(-C --color-output -M --monochrome-output)'{-C,--color-output}'[output with colors even if piped]' \
+ '(-C --color-output -M --monochrome-output)'{-M,--monochrome-output}'[output without colors]' \
'(-n --null-input)'{-n,--null-input}'[use null as input value]' \
- '(-R --raw-input)'{-R,--raw-input}'[read input as raw strings]' \
+ '(-R --raw-input --stream --yaml-input)'{-R,--raw-input}'[read input as raw strings]' \
+ '(-R --raw-input --yaml-input)--stream[parse input in stream fashion]' \
+ '(-R --raw-input --stream )--yaml-input[read input as YAML format]' \
'(-s --slurp)'{-s,--slurp}'[read all inputs into an array]' \
- '(--stream)'--stream'[parse input in stream fashion]' \
- '(--yaml-input)'--yaml-input'[read input as YAML]' \
- '(-f --from-file)'{-f,--from-file}'[load query from file]:filename of jq query:_files' \
- '(-L)'-L'[directory to search modules from]:module directory:_directories' \
- '(--arg)'--arg'[set variable to string value]:variable name:' \
- '(--argjson)'--argjson'[set variable to JSON value]:variable name:' \
- '(--slurpfile)'--slurpfile'[set variable to the JSON contents of the file]:variable name:' \
- '(--rawfile)'--rawfile'[set variable to the contents of the file]:variable name:' \
- '(--args)'--args'[consume remaining arguments as positional string values]' \
- '(--jsonargs)'--jsonargs'[consume remaining arguments as positional JSON values]' \
+ '(-f --from-file 1)'{-f,--from-file}='[load query from file]:filename of jq query:_files' \
+ '*-L=[directory to search modules from]:module directory:_directories' \
+ '*--arg[set a string value to a variable]:variable name: :string value' \
+ '*--argjson[set a JSON value to a variable]:variable name: :JSON value' \
+ '*--slurpfile[set the JSON contents of a file to a variable]:variable name: :JSON file:_files' \
+ '*--rawfile[set the contents of a file to a variable]:variable name: :file:_files' \
+ '*--args[consume remaining arguments as positional string values]' \
+ '*--jsonargs[consume remaining arguments as positional JSON values]' \
'(-e --exit-status)'{-e,--exit-status}'[exit 1 when the last value is false or null]' \
- '(-v --version)'{-v,--version}'[print version]' \
- '(-h --help)'{-h,--help}'[print help]' \
- && ret=0
+ '(- 1 *)'{-v,--version}'[display version information]' \
+ '(- 1 *)'{-h,--help}'[display help information]' \
+ '1: :_guard "^-([[:alpha:]0]#|-*)" "jq query"' \
+ '*: :_gojq_args'
+}
+
+_gojq_args() {
+ if (($words[(I)--args] > $words[(I)--jsonargs])); then
+ _message 'string value'
+ elif (($words[(I)--args] < $words[(I)--jsonargs])); then
+ _message 'JSON value'
+ else
+ _arguments '*:input file:_files'
+ fi
}
diff --git a/cli/cli.go b/cli/cli.go
index cc06135..a10ead5 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -17,7 +17,7 @@ import (
const name = "gojq"
-const version = "0.12.11"
+const version = "0.12.13"
var revision = "HEAD"
@@ -35,51 +35,51 @@ type cli struct {
outStream io.Writer
errStream io.Writer
- outputCompact bool
outputRaw bool
outputJoin bool
outputNul bool
- outputYAML bool
+ outputCompact bool
outputIndent *int
outputTab bool
+ outputYAML bool
inputRaw bool
- inputSlurp bool
inputStream bool
inputYAML bool
+ inputSlurp bool
argnames []string
- argvalues []interface{}
+ argvalues []any
outputYAMLSeparator bool
exitCodeError error
}
type flagopts struct {
- OutputCompact bool `short:"c" long:"compact-output" description:"compact output"`
OutputRaw bool `short:"r" long:"raw-output" description:"output raw strings"`
- OutputJoin bool `short:"j" long:"join-output" description:"stop printing a newline after each output"`
- OutputNul bool `short:"0" long:"nul-output" description:"print NUL after each output"`
- OutputColor bool `short:"C" long:"color-output" description:"colorize output even if piped"`
- OutputMono bool `short:"M" long:"monochrome-output" description:"stop colorizing output"`
- OutputYAML bool `long:"yaml-output" description:"output by YAML"`
+ OutputJoin bool `short:"j" long:"join-output" description:"output without newlines"`
+ OutputNul bool `short:"0" long:"nul-output" description:"output with NUL character"`
+ OutputCompact bool `short:"c" long:"compact-output" description:"output without pretty-printing"`
OutputIndent *int `long:"indent" description:"number of spaces for indentation"`
OutputTab bool `long:"tab" description:"use tabs for indentation"`
+ OutputYAML bool `long:"yaml-output" description:"output in YAML format"`
+ OutputColor bool `short:"C" long:"color-output" description:"output with colors even if piped"`
+ OutputMono bool `short:"M" long:"monochrome-output" description:"output without colors"`
InputNull bool `short:"n" long:"null-input" description:"use null as input value"`
InputRaw bool `short:"R" long:"raw-input" description:"read input as raw strings"`
- InputSlurp bool `short:"s" long:"slurp" description:"read all inputs into an array"`
InputStream bool `long:"stream" description:"parse input in stream fashion"`
- InputYAML bool `long:"yaml-input" description:"read input as YAML"`
+ InputYAML bool `long:"yaml-input" description:"read input as YAML format"`
+ InputSlurp bool `short:"s" long:"slurp" description:"read all inputs into an array"`
FromFile string `short:"f" long:"from-file" description:"load query from file"`
ModulePaths []string `short:"L" description:"directory to search modules from"`
- Arg map[string]string `long:"arg" description:"set variable to string value"`
- ArgJSON map[string]string `long:"argjson" description:"set variable to JSON value"`
- SlurpFile map[string]string `long:"slurpfile" description:"set variable to the JSON contents of the file"`
- RawFile map[string]string `long:"rawfile" description:"set variable to the contents of the file"`
- Args []interface{} `long:"args" positional:"" description:"consume remaining arguments as positional string values"`
- JSONArgs []interface{} `long:"jsonargs" positional:"" description:"consume remaining arguments as positional JSON values"`
+ Arg map[string]string `long:"arg" description:"set a string value to a variable"`
+ ArgJSON map[string]string `long:"argjson" description:"set a JSON value to a variable"`
+ SlurpFile map[string]string `long:"slurpfile" description:"set the JSON contents of a file to a variable"`
+ RawFile map[string]string `long:"rawfile" description:"set the contents of a file to a variable"`
+ Args []any `long:"args" positional:"" description:"consume remaining arguments as positional string values"`
+ JSONArgs []any `long:"jsonargs" positional:"" description:"consume remaining arguments as positional JSON values"`
ExitStatus bool `short:"e" long:"exit-status" description:"exit 1 when the last value is false or null"`
- Version bool `short:"v" long:"version" description:"print version"`
- Help bool `short:"h" long:"help" description:"print this help"`
+ Version bool `short:"v" long:"version" description:"display version information"`
+ Help bool `short:"h" long:"help" description:"display this help information"`
}
var addDefaultModulePaths = true
@@ -121,10 +121,10 @@ Usage:
fmt.Fprintf(cli.outStream, "%s %s (rev: %s/%s)\n", name, version, revision, runtime.Version())
return nil
}
- cli.outputCompact, cli.outputRaw, cli.outputJoin, cli.outputNul,
- cli.outputYAML, cli.outputIndent, cli.outputTab =
- opts.OutputCompact, opts.OutputRaw, opts.OutputJoin, opts.OutputNul,
- opts.OutputYAML, opts.OutputIndent, opts.OutputTab
+ cli.outputRaw, cli.outputJoin, cli.outputNul,
+ cli.outputCompact, cli.outputIndent, cli.outputTab, cli.outputYAML =
+ opts.OutputRaw, opts.OutputJoin, opts.OutputNul,
+ opts.OutputCompact, opts.OutputIndent, opts.OutputTab, opts.OutputYAML
defer func(x bool) { noColor = x }(noColor)
if opts.OutputColor || opts.OutputMono {
noColor = opts.OutputMono
@@ -151,8 +151,8 @@ Usage:
if opts.OutputYAML && opts.OutputTab {
return errors.New("cannot use tabs for YAML output")
}
- cli.inputRaw, cli.inputSlurp, cli.inputStream, cli.inputYAML =
- opts.InputRaw, opts.InputSlurp, opts.InputStream, opts.InputYAML
+ cli.inputRaw, cli.inputStream, cli.inputYAML, cli.inputSlurp =
+ opts.InputRaw, opts.InputStream, opts.InputYAML, opts.InputSlurp
for k, v := range opts.Arg {
cli.argnames = append(cli.argnames, "$"+k)
cli.argvalues = append(cli.argvalues, v)
@@ -181,7 +181,7 @@ Usage:
cli.argnames = append(cli.argnames, "$"+k)
cli.argvalues = append(cli.argvalues, string(val))
}
- named := make(map[string]interface{}, len(cli.argnames))
+ named := make(map[string]any, len(cli.argnames))
for i, name := range cli.argnames {
named[name[1:]] = cli.argvalues[i]
}
@@ -200,7 +200,7 @@ Usage:
}
}
cli.argnames = append(cli.argnames, "$ARGS")
- cli.argvalues = append(cli.argvalues, map[string]interface{}{
+ cli.argvalues = append(cli.argvalues, map[string]any{
"named": named,
"positional": positional,
})
@@ -242,8 +242,8 @@ Usage:
gojq.WithFunction("debug", 0, 0, cli.funcDebug),
gojq.WithFunction("stderr", 0, 0, cli.funcStderr),
gojq.WithFunction("input_filename", 0, 0,
- func(iter inputIter) func(interface{}, []interface{}) interface{} {
- return func(interface{}, []interface{}) interface{} {
+ func(iter inputIter) func(any, []any) any {
+ return func(any, []any) any {
if fname := iter.Name(); fname != "" && (len(args) > 0 || !opts.InputNull) {
return fname
}
@@ -291,7 +291,7 @@ func listDefaultModulePaths() []string {
return modulePaths
}
-func slurpFile(name string) (interface{}, error) {
+func slurpFile(name string) (any, error) {
iter := newSlurpInputIter(
newFilesInputIter(newJSONInputIter, []string{name}, nil),
)
@@ -408,14 +408,20 @@ func (cli *cli) createMarshaler() marshaler {
return f
}
-func (cli *cli) funcDebug(v interface{}, _ []interface{}) interface{} {
- newEncoder(false, 0).marshal([]interface{}{"DEBUG:", v}, cli.errStream)
- cli.errStream.Write([]byte{'\n'})
+func (cli *cli) funcDebug(v any, _ []any) any {
+ if err := newEncoder(false, 0).marshal([]any{"DEBUG:", v}, cli.errStream); err != nil {
+ return err
+ }
+ if _, err := cli.errStream.Write([]byte{'\n'}); err != nil {
+ return err
+ }
return v
}
-func (cli *cli) funcStderr(v interface{}, _ []interface{}) interface{} {
- newEncoder(false, 0).marshal(v, cli.errStream)
+func (cli *cli) funcStderr(v any, _ []any) any {
+ if err := newEncoder(false, 0).marshal(v, cli.errStream); err != nil {
+ return err
+ }
return v
}
diff --git a/cli/encoder.go b/cli/encoder.go
index 2f6edee..8841baa 100644
--- a/cli/encoder.go
+++ b/cli/encoder.go
@@ -31,7 +31,7 @@ func (e *encoder) flush() error {
return err
}
-func (e *encoder) marshal(v interface{}, w io.Writer) error {
+func (e *encoder) marshal(v any, w io.Writer) error {
e.out = w
err := e.encode(v)
if ferr := e.flush(); ferr != nil && err == nil {
@@ -40,7 +40,7 @@ func (e *encoder) marshal(v interface{}, w io.Writer) error {
return err
}
-func (e *encoder) encode(v interface{}) error {
+func (e *encoder) encode(v any) error {
switch v := v.(type) {
case nil:
e.write([]byte("null"), nullColor)
@@ -58,12 +58,12 @@ func (e *encoder) encode(v interface{}) error {
e.write(v.Append(e.buf[:0], 10), numberColor)
case string:
e.encodeString(v, stringColor)
- case []interface{}:
+ case []any:
if err := e.encodeArray(v); err != nil {
return err
}
- case map[string]interface{}:
- if err := e.encodeMap(v); err != nil {
+ case map[string]any:
+ if err := e.encodeObject(v); err != nil {
return err
}
default:
@@ -86,12 +86,12 @@ func (e *encoder) encodeFloat64(f float64) {
} else if f <= -math.MaxFloat64 {
f = -math.MaxFloat64
}
- fmt := byte('f')
+ format := byte('f')
if x := math.Abs(f); x != 0 && x < 1e-6 || x >= 1e21 {
- fmt = 'e'
+ format = 'e'
}
- buf := strconv.AppendFloat(e.buf[:0], f, fmt, -1, 64)
- if fmt == 'e' {
+ buf := strconv.AppendFloat(e.buf[:0], f, format, -1, 64)
+ if format == 'e' {
// clean up e-09 to e-9
if n := len(buf); n >= 4 && buf[n-4] == 'e' && buf[n-3] == '-' && buf[n-2] == '0' {
buf[n-2] = buf[n-1]
@@ -163,7 +163,7 @@ func (e *encoder) encodeString(s string, color []byte) {
}
}
-func (e *encoder) encodeArray(vs []interface{}) error {
+func (e *encoder) encodeArray(vs []any) error {
e.writeByte('[', arrayColor)
e.depth += e.indent
for i, v := range vs {
@@ -185,12 +185,12 @@ func (e *encoder) encodeArray(vs []interface{}) error {
return nil
}
-func (e *encoder) encodeMap(vs map[string]interface{}) error {
+func (e *encoder) encodeObject(vs map[string]any) error {
e.writeByte('{', objectColor)
e.depth += e.indent
type keyVal struct {
key string
- val interface{}
+ val any
}
kvs := make([]keyVal, len(vs))
var i int
diff --git a/cli/flags.go b/cli/flags.go
index aab827b..fb3e34e 100644
--- a/cli/flags.go
+++ b/cli/flags.go
@@ -7,7 +7,7 @@ import (
"strings"
)
-func parseFlags(args []string, opts interface{}) ([]string, error) {
+func parseFlags(args []string, opts any) ([]string, error) {
rest := make([]string, 0, len(args))
val := reflect.ValueOf(opts).Elem()
typ := val.Type()
@@ -158,7 +158,7 @@ func parseFlags(args []string, opts interface{}) ([]string, error) {
return rest, nil
}
-func formatFlags(opts interface{}) string {
+func formatFlags(opts any) string {
val := reflect.ValueOf(opts).Elem()
typ := val.Type()
var sb strings.Builder
diff --git a/cli/inputs.go b/cli/inputs.go
index cf655af..1f91c48 100644
--- a/cli/inputs.go
+++ b/cli/inputs.go
@@ -83,11 +83,11 @@ func newJSONInputIter(r io.Reader, fname string) inputIter {
return &jsonInputIter{dec: dec, ir: ir, fname: fname}
}
-func (i *jsonInputIter) Next() (interface{}, bool) {
+func (i *jsonInputIter) Next() (any, bool) {
if i.err != nil {
return nil, false
}
- var v interface{}
+ var v any
if err := i.dec.Decode(&v); err != nil {
if err == io.EOF {
i.err = err
@@ -127,7 +127,7 @@ func newNullInputIter() inputIter {
return &nullInputIter{}
}
-func (i *nullInputIter) Next() (interface{}, bool) {
+func (i *nullInputIter) Next() (any, bool) {
if i.err != nil {
return nil, false
}
@@ -159,7 +159,7 @@ func newFilesInputIter(
return &filesInputIter{newIter: newIter, fnames: fnames, stdin: stdin}
}
-func (i *filesInputIter) Next() (interface{}, bool) {
+func (i *filesInputIter) Next() (any, bool) {
if i.err != nil {
return nil, false
}
@@ -227,7 +227,7 @@ func newRawInputIter(r io.Reader, fname string) inputIter {
return &rawInputIter{r: bufio.NewReader(r), fname: fname}
}
-func (i *rawInputIter) Next() (interface{}, bool) {
+func (i *rawInputIter) Next() (any, bool) {
if i.err != nil {
return nil, false
}
@@ -269,7 +269,7 @@ func newStreamInputIter(r io.Reader, fname string) inputIter {
return &streamInputIter{stream: newJSONStream(dec), ir: ir, fname: fname}
}
-func (i *streamInputIter) Next() (interface{}, bool) {
+func (i *streamInputIter) Next() (any, bool) {
if i.err != nil {
return nil, false
}
@@ -318,11 +318,11 @@ func newYAMLInputIter(r io.Reader, fname string) inputIter {
return &yamlInputIter{dec: dec, ir: ir, fname: fname}
}
-func (i *yamlInputIter) Next() (interface{}, bool) {
+func (i *yamlInputIter) Next() (any, bool) {
if i.err != nil {
return nil, false
}
- var v interface{}
+ var v any
if err := i.dec.Decode(&v); err != nil {
if err == io.EOF {
i.err = err
@@ -352,12 +352,12 @@ func newSlurpInputIter(iter inputIter) inputIter {
return &slurpInputIter{iter: iter}
}
-func (i *slurpInputIter) Next() (interface{}, bool) {
+func (i *slurpInputIter) Next() (any, bool) {
if i.err != nil {
return nil, false
}
- var vs []interface{}
- var v interface{}
+ var vs []any
+ var v any
var ok bool
for {
v, ok = i.iter.Next()
@@ -395,7 +395,7 @@ func newReadAllIter(r io.Reader, fname string) inputIter {
return &readAllIter{r: r, fname: fname}
}
-func (i *readAllIter) Next() (interface{}, bool) {
+func (i *readAllIter) Next() (any, bool) {
if i.err != nil {
return nil, false
}
@@ -425,12 +425,12 @@ func newSlurpRawInputIter(iter inputIter) inputIter {
return &slurpRawInputIter{iter: iter}
}
-func (i *slurpRawInputIter) Next() (interface{}, bool) {
+func (i *slurpRawInputIter) Next() (any, bool) {
if i.err != nil {
return nil, false
}
var vs []string
- var v interface{}
+ var v any
var ok bool
for {
v, ok = i.iter.Next()
diff --git a/cli/marshaler.go b/cli/marshaler.go
index 8b6ae9f..9c38e7a 100644
--- a/cli/marshaler.go
+++ b/cli/marshaler.go
@@ -7,14 +7,14 @@ import (
)
type marshaler interface {
- marshal(interface{}, io.Writer) error
+ marshal(any, io.Writer) error
}
type rawMarshaler struct {
m marshaler
}
-func (m *rawMarshaler) marshal(v interface{}, w io.Writer) error {
+func (m *rawMarshaler) marshal(v any, w io.Writer) error {
if s, ok := v.(string); ok {
_, err := w.Write([]byte(s))
return err
@@ -30,7 +30,7 @@ type yamlMarshaler struct {
indent *int
}
-func (m *yamlMarshaler) marshal(v interface{}, w io.Writer) error {
+func (m *yamlMarshaler) marshal(v any, w io.Writer) error {
enc := yaml.NewEncoder(w)
if i := m.indent; i != nil {
enc.SetIndent(*i)
diff --git a/cli/stream.go b/cli/stream.go
index e647711..d9285cc 100644
--- a/cli/stream.go
+++ b/cli/stream.go
@@ -7,12 +7,12 @@ import (
type jsonStream struct {
dec *json.Decoder
- path []interface{}
+ path []any
states []int
}
func newJSONStream(dec *json.Decoder) *jsonStream {
- return &jsonStream{dec: dec, states: []int{jsonStateTopValue}, path: []interface{}{}}
+ return &jsonStream{dec: dec, states: []int{jsonStateTopValue}, path: []any{}}
}
const (
@@ -28,7 +28,7 @@ const (
jsonStateObjectEmptyEnd
)
-func (s *jsonStream) next() (interface{}, error) {
+func (s *jsonStream) next() (any, error) {
switch s.states[len(s.states)-1] {
case jsonStateArrayEnd, jsonStateObjectEnd:
s.path = s.path[:len(s.path)-1]
@@ -71,17 +71,17 @@ func (s *jsonStream) next() (interface{}, error) {
if s.states[len(s.states)-1] == jsonStateArrayStart {
s.states[len(s.states)-1] = jsonStateArrayEmptyEnd
s.path = s.path[:len(s.path)-1]
- return []interface{}{s.copyPath(), []interface{}{}}, nil
+ return []any{s.copyPath(), []any{}}, nil
}
s.states[len(s.states)-1] = jsonStateArrayEnd
- return []interface{}{s.copyPath()}, nil
+ return []any{s.copyPath()}, nil
case '}':
if s.states[len(s.states)-1] == jsonStateObjectStart {
s.states[len(s.states)-1] = jsonStateObjectEmptyEnd
- return []interface{}{s.copyPath(), map[string]interface{}{}}, nil
+ return []any{s.copyPath(), map[string]any{}}, nil
}
s.states[len(s.states)-1] = jsonStateObjectEnd
- return []interface{}{s.copyPath()}, nil
+ return []any{s.copyPath()}, nil
default:
panic(d)
}
@@ -91,23 +91,23 @@ func (s *jsonStream) next() (interface{}, error) {
s.states[len(s.states)-1] = jsonStateArrayValue
fallthrough
case jsonStateArrayValue:
- return []interface{}{s.copyPath(), token}, nil
+ return []any{s.copyPath(), token}, nil
case jsonStateObjectStart, jsonStateObjectValue:
s.states[len(s.states)-1] = jsonStateObjectKey
s.path = append(s.path, token)
case jsonStateObjectKey:
s.states[len(s.states)-1] = jsonStateObjectValue
- return []interface{}{s.copyPath(), token}, nil
+ return []any{s.copyPath(), token}, nil
default:
s.states[len(s.states)-1] = jsonStateTopValue
- return []interface{}{s.copyPath(), token}, nil
+ return []any{s.copyPath(), token}, nil
}
}
}
}
-func (s *jsonStream) copyPath() []interface{} {
- path := make([]interface{}, len(s.path))
+func (s *jsonStream) copyPath() []any {
+ path := make([]any, len(s.path))
copy(path, s.path)
return path
}
diff --git a/cli/test.yaml b/cli/test.yaml
index 63fc028..4582944 100644
--- a/cli/test.yaml
+++ b/cli/test.yaml
@@ -1264,7 +1264,7 @@
- 'has(0)'
input: '{}'
error: |
- cannot check whether object ({}) has a key: number (0)
+ has(0) cannot be applied to: object ({})
- name: in function for object
args:
@@ -1296,7 +1296,7 @@
- 'in([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])'
input: '"x"'
error: |
- cannot check whether array ([0,0,0,0,0,0,0,0,0,0,0,0, ...]) has a key: string ("x")
+ has("x") cannot be applied to: array ([0,0,0,0,0,0,0,0,0,0,0,0, ...])
- name: map function
args:
@@ -1330,7 +1330,14 @@
- 'from_entries'
input: '[{"value":1}]'
error: |
- expected a string for object key but got: null
+ from_entries cannot be applied to [{"value":1}]: expected a string for object key but got: null
+
+- name: from_entries function key type error
+ args:
+ - 'from_entries'
+ input: '[{"key":{},"value":1}]'
+ error: |
+ from_entries cannot be applied to [{"key":{},"value":1}]: expected a string for object key but got: object ({})
- name: with_entries function
args:
@@ -1445,7 +1452,7 @@
- 'flatten(-1)'
input: '[]'
error: |
- flatten depth must not be negative: number (-1)
+ flatten depth should not be negative: -1
- name: min, min_by, max, max_by functions
args:
@@ -1709,12 +1716,12 @@
".e1"
"-.e"
expected: |
- "invalid number: \"\""
- "invalid number: \".\""
- "invalid number: \" \""
- "invalid number: \"1a\""
- "invalid number: \".e1\""
- "invalid number: \"-.e\""
+ "tonumber cannot be applied to \"\": invalid number"
+ "tonumber cannot be applied to \".\": invalid number"
+ "tonumber cannot be applied to \" \": invalid number"
+ "tonumber cannot be applied to \"1a\": invalid number"
+ "tonumber cannot be applied to \".e1\": invalid number"
+ "tonumber cannot be applied to \"-.e\": invalid number"
- name: tostring function
args:
@@ -1818,7 +1825,7 @@
- 'nan | contains([nan])'
input: '0'
error: |
- cannot check contains([null]): number (null)
+ contains([null]) cannot be applied to: number (null)
- name: indices, index, rindex functions against null
args:
@@ -1868,6 +1875,15 @@
[0,1,3]
[5,1,3]
+- name: indices, index, rindex functions type error
+ args:
+ - '(try indices([]) catch .), (try index([]) catch .), (try rindex([]) catch .)'
+ input: '{}'
+ expected: |
+ "indices([]) cannot be applied to: object ({})"
+ "index([]) cannot be applied to: object ({})"
+ "rindex([]) cannot be applied to: object ({})"
+
- name: inside function
args:
- -c
@@ -1901,8 +1917,8 @@
- '("x" | try startswith({}) catch .), (10 | try startswith("x") catch .)'
input: '0'
expected: |
- "startswith cannot be applied to: object ({})"
- "startswith cannot be applied to: number (10)"
+ "startswith({}) cannot be applied to: string (\"x\")"
+ "startswith(\"x\") cannot be applied to: number (10)"
- name: endswith function
args:
@@ -1925,8 +1941,8 @@
- '("x" | try endswith({}) catch .), (10 | try endswith("x") catch .)'
input: '0'
expected: |
- "endswith cannot be applied to: object ({})"
- "endswith cannot be applied to: number (10)"
+ "endswith({}) cannot be applied to: string (\"x\")"
+ "endswith(\"x\") cannot be applied to: number (10)"
- name: combinations/0 function
args:
@@ -2084,18 +2100,18 @@
- 'try join(",") catch .'
input: '["1","2",[3,4,5]]'
expected: |
- "cannot join: array ([3,4,5])"
+ "join cannot be applied to an array including: array ([3,4,5])"
- name: join function error input
args:
- '.[] | try join(",") catch .'
input: '[null, false, true, 1, "a"]'
expected: |
- "join cannot be applied to: null"
- "join cannot be applied to: boolean (false)"
- "join cannot be applied to: boolean (true)"
- "join cannot be applied to: number (1)"
- "join cannot be applied to: string (\"a\")"
+ "join(\",\") cannot be applied to: null"
+ "join(\",\") cannot be applied to: boolean (false)"
+ "join(\",\") cannot be applied to: boolean (true)"
+ "join(\",\") cannot be applied to: number (1)"
+ "join(\",\") cannot be applied to: string (\"a\")"
- name: join function non-string separator
args:
@@ -2104,7 +2120,7 @@
expected: |
""
"1"
- "join cannot be applied to: number (1)"
+ "join(1) cannot be applied to: array ([1,2])"
- name: ascii_downcase function
args:
@@ -2647,9 +2663,16 @@
- name: multiply empty string
args:
- - '7 * ""'
+ - '(-9223372036854775808, -1, 0, 0.001, 0.999, 1, 7, 9223372036854775807) * ""'
input: 'null'
expected: |
+ null
+ null
+ null
+ ""
+ ""
+ ""
+ ""
""
- name: multiply objects
@@ -3389,6 +3412,13 @@
["foo"]
{"a":[1,2,3]}
+- name: fromjson function error
+ args:
+ - 'fromjson'
+ input: '"[0"'
+ error: |
+ fromjson cannot be applied to "[0": unexpected EOF
+
- name: variable definition
args:
- -c
@@ -4200,49 +4230,49 @@
- 'setpath([-1]; 10)'
input: '[]'
error: |
- setpath cannot be applied to: number (-1)
+ setpath([-1]; 10) cannot be applied to []: array index should not be negative: -1
- name: setpath function error
args:
- 'setpath(["a","b","c"]; 10)'
input: '{"a":{"b":[]}}'
error: |
- expected an object but got: array ([])
+ setpath(["a","b","c"]; 10) cannot be applied to {"a":{"b":[]}}: expected an object but got: array ([])
- name: setpath function error
args:
- 'setpath(["a",1]; 10)'
input: '{"a":{"b":[]}}'
error: |
- expected an array but got: object ({"b":[]})
+ setpath(["a",1]; 10) cannot be applied to {"a":{"b":[]}}: expected an array but got: object ({"b":[]})
- name: setpath function error
args:
- 'setpath([{}]; 10)'
input: 'null'
error: |
- expected "start" and "end" for slicing but got: object ({})
+ setpath([{}]; 10) cannot be applied to null: expected "start" and "end" for slicing but got: object ({})
- name: setpath function error
args:
- 'setpath([{start:0}]; 10)'
input: 'null'
error: |
- expected "start" and "end" for slicing but got: object ({"start":0})
+ setpath([{"start":0}]; 10) cannot be applied to null: expected "start" and "end" for slicing but got: object ({"start":0})
- name: setpath function error
args:
- 'setpath([[]]; 10)'
input: '[]'
error: |
- expected a number for indexing an array but got: array ([])
+ setpath([[]]; 10) cannot be applied to []: expected a number for indexing an array but got: array ([])
- name: setpath function error
args:
- 'setpath([{start:0,end:1}]; 10)'
input: '[]'
error: |
- expected an array but got: number (10)
+ setpath([{"end":1,"start":0}]; 10) cannot be applied to []: expected an array but got: number (10)
- name: delpaths function
args:
@@ -4286,6 +4316,20 @@
{"x":[]}
{}
+- name: delpaths function error
+ args:
+ - 'delpaths([{}])'
+ input: '[]'
+ error: |
+ delpaths([{}]) cannot be applied to []: expected an array but got: object ({})
+
+- name: delpaths function error
+ args:
+ - 'delpaths([["x"]])'
+ input: '[]'
+ error: |
+ delpaths([["x"]]) cannot be applied to []: expected an object but got: array ([])
+
- name: getpath function
args:
- -c
@@ -4307,7 +4351,7 @@
- 'getpath(["a",1,"b","c"])'
input: '{"a":[{},{"b":[1,2,3,4,5,6,7]}]}'
error: |
- cannot getpath with ["a",1,"b","c"] against: object ({"a":[{},{"b":[1,2,3,4,5, ...})
+ getpath(["a",1,"b","c"]) cannot be applied to {"a":[{},{"b":[1,2,3,4,5, ...}: expected an object but got: array ([1,2,3,4,5,6,7])
- name: setpath, delpaths, getpath functions
args:
@@ -4334,10 +4378,10 @@
expected: |
{"a":[{"b":5}]}
{"a":[{"b":5}],"b":0}
- "cannot getpath with [\"a\",0,\"b\"] against: object ({\"a\":0})"
+ "getpath([\"a\",0,\"b\"]) cannot be applied to: object ({\"a\":0})"
{"a":[{"b":5}]}
- "cannot getpath with [\"a\",0,\"b\"] against: object ({\"a\":[0,1]})"
- "cannot getpath with [\"a\",0,\"b\"] against: object ({\"a\":{\"b\":1}})"
+ "getpath([\"a\",0,\"b\"]) cannot be applied to: object ({\"a\":[0,1]})"
+ "getpath([\"a\",0,\"b\"]) cannot be applied to {\"a\":{\"b\":1}}: expected an array but got: object ({\"b\":1})"
{"a":[{"b":5}]}
{"a":[{"b":5,"c":3}]}
@@ -4509,7 +4553,7 @@
expected: |
[{"x":{"y":{"z":{}}}},{"x":{}}]
-- name: assignment operator query
+- name: assignment operator with query value
args:
- -c
- '.foo = .bar'
@@ -4517,7 +4561,7 @@
expected: |
{"bar":42,"foo":42}
-- name: assignment operator query with multiple paths and values
+- name: assignment operator with multiple paths and query values
args:
- -c
- '(.foo,.bar,.baz) = .bar[]'
@@ -4527,12 +4571,35 @@
{"bar":1,"baz":1,"foo":1}
{"bar":2,"baz":2,"foo":2}
+- name: assignment operator with overlapping paths and multiple values
+ args:
+ - -c
+ - '.. = ..'
+ input: '{"x":{"y":{}}} [[[]]]'
+ expected: |
+ {"x":{"x":{"y":{}},"y":{"x":{"y":{}}}}}
+ {"x":{"y":{"y":{}}},"y":{}}
+ {"x":{"y":{}}}
+ [[[[[]]]]]
+ [[[[]]]]
+ [[[]]]
+
+- name: assignment operator with overlapping and slicing paths
+ args:
+ - -c
+ - '..[:0] = ..'
+ input: '[[[]]]'
+ expected: |
+ [[[[[]],[]],[]],[[]]]
+ [[[[]]],[[]]]
+ [[[]]]
+
- name: assignment operator array index negative error
args:
- '.[-1,0] = 1'
input: '[]'
error: |
- setpath cannot be applied to: number (-1)
+ setpath([-1]; 1) cannot be applied to []: array index should not be negative: -1
- name: assignment operator array index limit error
args:
@@ -5688,6 +5755,13 @@
[{"captures":[{"length":1,"name":"foo","offset":2,"string":"c"},{"length":1,"name":null,"offset":3,"string":"d"}],"length":3,"offset":1,"string":"bcd"},{"captures":[{"length":1,"name":"foo","offset":9,"string":"c"},{"length":1,"name":null,"offset":10,"string":"d"}],"length":3,"offset":8,"string":"bcd"},{"captures":[{"length":1,"name":"foo","offset":16,"string":"C"},{"length":1,"name":null,"offset":17,"string":"D"}],"length":3,"offset":15,"string":"BCD"}]
[{"captures":[{"length":0,"name":null,"offset":-1,"string":null},{"length":0,"name":null,"offset":-1,"string":null}],"length":3,"offset":1,"string":"bcd"}]
+- name: match function type error
+ args:
+ - 'match("x"; "g")'
+ input: '{}'
+ error: |
+ match("x"; "g") cannot be applied to: object ({})
+
- name: match function flag error
args:
- 'match("x"; "a")'
@@ -5695,6 +5769,13 @@
error: |
unsupported regular expression flag: "a"
+- name: match function regular expression error
+ args:
+ - 'match("["; "g")'
+ input: '""'
+ error: |
+ invalid regular expression "[": error parsing regexp: missing closing ]: `[`
+
- name: test function
args:
- -c
@@ -5876,6 +5957,22 @@
expected: |
"q=%5B%22%3C%3E%22%2C%22%7B%26%7D%22%5D&q=%5B%22%3C%3E%22%2C%22%7B%26%7D%22%2C%22%3C%3E%22%2C%22%7B%26%7D%22%5D"
+- name: format strings @urid
+ args:
+ - '@urid'
+ input: |
+ "%5B1%2C%7B%22foo%22%3A%22%3Cdiv%3E%26%27%5C%22%28%29%3C%2Fdiv%3E%22%7D%5D"
+ expected: |
+ "[1,{\"foo\":\"<div>&'\\\"()</div>\"}]"
+
+- name: format strings @urid error
+ args:
+ - '@urid'
+ input: |
+ "%5B1%2C%"
+ error: |
+ @urid cannot be applied to "%5B1%2C%": invalid URL escape "%"
+
- name: format strings @csv
args:
- '@csv'
@@ -5996,6 +6093,14 @@
expected: |
"{\"foo\":\"bar\"}"
+- name: format strings @base64d error
+ args:
+ - '@base64d'
+ input: |
+ ":"
+ error: |
+ @base64d cannot be applied to ":": illegal base64 data at input byte 0
+
- name: format strings not defined error
args:
- -n
diff --git a/cli/yaml.go b/cli/yaml.go
index f72f10d..652bdb2 100644
--- a/cli/yaml.go
+++ b/cli/yaml.go
@@ -6,23 +6,23 @@ import (
)
// Workaround for https://github.com/go-yaml/yaml/issues/139
-func normalizeYAML(v interface{}) interface{} {
+func normalizeYAML(v any) any {
switch v := v.(type) {
- case map[interface{}]interface{}:
- w := make(map[string]interface{}, len(v))
+ case map[any]any:
+ w := make(map[string]any, len(v))
for k, v := range v {
w[fmt.Sprint(k)] = normalizeYAML(v)
}
return w
- case map[string]interface{}:
- w := make(map[string]interface{}, len(v))
+ case map[string]any:
+ w := make(map[string]any, len(v))
for k, v := range v {
w[k] = normalizeYAML(v)
}
return w
- case []interface{}:
+ case []any:
for i, w := range v {
v[i] = normalizeYAML(w)
}
diff --git a/code.go b/code.go
index efac134..33505bd 100644
--- a/code.go
+++ b/code.go
@@ -1,7 +1,7 @@
package gojq
type code struct {
- v interface{}
+ v any
op opcode
}
diff --git a/compare.go b/compare.go
index 89f0cdf..e70c1fb 100644
--- a/compare.go
+++ b/compare.go
@@ -8,14 +8,14 @@ import (
// Compare l and r, and returns jq-flavored comparison value.
// The result will be 0 if l == r, -1 if l < r, and +1 if l > r.
// This comparison is used by built-in operators and functions.
-func Compare(l, r interface{}) int {
+func Compare(l, r any) int {
return compare(l, r)
}
-func compare(l, r interface{}) int {
+func compare(l, r any) int {
return binopTypeSwitch(l, r,
compareInt,
- func(l, r float64) interface{} {
+ func(l, r float64) any {
switch {
case l < r || math.IsNaN(l):
return -1
@@ -25,10 +25,10 @@ func compare(l, r interface{}) int {
return 1
}
},
- func(l, r *big.Int) interface{} {
+ func(l, r *big.Int) any {
return l.Cmp(r)
},
- func(l, r string) interface{} {
+ func(l, r string) any {
switch {
case l < r:
return -1
@@ -38,7 +38,7 @@ func compare(l, r interface{}) int {
return 1
}
},
- func(l, r []interface{}) interface{} {
+ func(l, r []any) any {
n := len(l)
if len(r) < n {
n = len(r)
@@ -50,25 +50,25 @@ func compare(l, r interface{}) int {
}
return compareInt(len(l), len(r))
},
- func(l, r map[string]interface{}) interface{} {
+ func(l, r map[string]any) any {
lk, rk := funcKeys(l), funcKeys(r)
if cmp := compare(lk, rk); cmp != 0 {
return cmp
}
- for _, k := range lk.([]interface{}) {
+ for _, k := range lk.([]any) {
if cmp := compare(l[k.(string)], r[k.(string)]); cmp != 0 {
return cmp
}
}
return 0
},
- func(l, r interface{}) interface{} {
+ func(l, r any) any {
return compareInt(typeIndex(l), typeIndex(r))
},
).(int)
}
-func compareInt(l, r int) interface{} {
+func compareInt(l, r int) any {
switch {
case l < r:
return -1
@@ -79,7 +79,7 @@ func compareInt(l, r int) interface{} {
}
}
-func typeIndex(v interface{}) int {
+func typeIndex(v any) int {
switch v := v.(type) {
default:
return 0
@@ -92,9 +92,9 @@ func typeIndex(v interface{}) int {
return 3
case string:
return 4
- case []interface{}:
+ case []any:
return 5
- case map[string]interface{}:
+ case map[string]any:
return 6
}
}
diff --git a/compare_test.go b/compare_test.go
index e996037..f05e990 100644
--- a/compare_test.go
+++ b/compare_test.go
@@ -11,7 +11,7 @@ import (
func TestCompare(t *testing.T) {
testCases := []struct {
- l, r interface{}
+ l, r any
expected int
}{
{nil, nil, 0},
@@ -44,24 +44,24 @@ func TestCompare(t *testing.T) {
{"", "abc", -1},
{"abc", "", 1},
{"abc", "abc", 0},
- {"", []interface{}{}, -1},
- {[]interface{}{}, "", 1},
- {[]interface{}{}, []interface{}{}, 0},
- {[]interface{}{}, []interface{}{nil}, -1},
- {[]interface{}{nil}, []interface{}{}, 1},
- {[]interface{}{nil}, []interface{}{nil}, 0},
- {[]interface{}{0, 1, 2}, []interface{}{0, 1, nil}, 1},
- {[]interface{}{0, 1, 2}, []interface{}{0, 1, 2, nil}, -1},
- {[]interface{}{0, 1, 2, false, nil}, []interface{}{0, 1, 2, nil, false}, 1},
- {[]interface{}{}, map[string]interface{}{}, -1},
- {map[string]interface{}{}, []interface{}{}, 1},
- {map[string]interface{}{}, map[string]interface{}{}, 0},
- {map[string]interface{}{"a": nil}, map[string]interface{}{"a": nil}, 0},
- {map[string]interface{}{"a": nil}, map[string]interface{}{"a": nil, "b": nil}, -1},
- {map[string]interface{}{"a": nil, "b": nil}, map[string]interface{}{"a": nil, "c": nil}, -1},
- {map[string]interface{}{"a": 0, "b": 0, "c": 0}, map[string]interface{}{"a": 0, "b": 0, "c": 0}, 0},
- {map[string]interface{}{"a": 0, "b": 0, "d": 0}, map[string]interface{}{"a": 0, "b": 1, "c": 0}, 1},
- {map[string]interface{}{"a": 0, "b": 1, "c": 2}, map[string]interface{}{"a": 0, "b": 2, "c": 1}, -1},
+ {"", []any{}, -1},
+ {[]any{}, "", 1},
+ {[]any{}, []any{}, 0},
+ {[]any{}, []any{nil}, -1},
+ {[]any{nil}, []any{}, 1},
+ {[]any{nil}, []any{nil}, 0},
+ {[]any{0, 1, 2}, []any{0, 1, nil}, 1},
+ {[]any{0, 1, 2}, []any{0, 1, 2, nil}, -1},
+ {[]any{0, 1, 2, false, nil}, []any{0, 1, 2, nil, false}, 1},
+ {[]any{}, map[string]any{}, -1},
+ {map[string]any{}, []any{}, 1},
+ {map[string]any{}, map[string]any{}, 0},
+ {map[string]any{"a": nil}, map[string]any{"a": nil}, 0},
+ {map[string]any{"a": nil}, map[string]any{"a": nil, "b": nil}, -1},
+ {map[string]any{"a": nil, "b": nil}, map[string]any{"a": nil, "c": nil}, -1},
+ {map[string]any{"a": 0, "b": 0, "c": 0}, map[string]any{"a": 0, "b": 0, "c": 0}, 0},
+ {map[string]any{"a": 0, "b": 0, "d": 0}, map[string]any{"a": 0, "b": 1, "c": 0}, 1},
+ {map[string]any{"a": 0, "b": 1, "c": 2}, map[string]any{"a": 0, "b": 2, "c": 1}, -1},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%v,%v", tc.l, tc.r), func(t *testing.T) {
diff --git a/compiler.go b/compiler.go
index c750c47..de5f9a1 100644
--- a/compiler.go
+++ b/compiler.go
@@ -35,12 +35,12 @@ type Code struct {
//
// It is safe to call this method in goroutines, to reuse a compiled [*Code].
// But for arguments, do not give values sharing same data between goroutines.
-func (c *Code) Run(v interface{}, values ...interface{}) Iter {
+func (c *Code) Run(v any, values ...any) Iter {
return c.RunWithContext(context.Background(), v, values...)
}
// RunWithContext runs the code with context.
-func (c *Code) RunWithContext(ctx context.Context, v interface{}, values ...interface{}) Iter {
+func (c *Code) RunWithContext(ctx context.Context, v any, values ...any) Iter {
if len(values) > len(c.variables) {
return NewIter(&tooManyVariableValuesError{})
} else if len(values) < len(c.variables) {
@@ -144,15 +144,15 @@ func (c *compiler) compileImport(i *Import) error {
return fmt.Errorf("cannot load module: %q", path)
}
if strings.HasPrefix(alias, "$") {
- var vals interface{}
+ var vals any
if moduleLoader, ok := c.moduleLoader.(interface {
- LoadJSONWithMeta(string, map[string]interface{}) (interface{}, error)
+ LoadJSONWithMeta(string, map[string]any) (any, error)
}); ok {
if vals, err = moduleLoader.LoadJSONWithMeta(path, i.Meta.ToValue()); err != nil {
return err
}
} else if moduleLoader, ok := c.moduleLoader.(interface {
- LoadJSON(string) (interface{}, error)
+ LoadJSON(string) (any, error)
}); ok {
if vals, err = moduleLoader.LoadJSON(path); err != nil {
return err
@@ -169,7 +169,7 @@ func (c *compiler) compileImport(i *Import) error {
}
var q *Query
if moduleLoader, ok := c.moduleLoader.(interface {
- LoadModuleWithMeta(string, map[string]interface{}) (*Query, error)
+ LoadModuleWithMeta(string, map[string]any) (*Query, error)
}); ok {
if q, err = moduleLoader.LoadModuleWithMeta(path, i.Meta.ToValue()); err != nil {
return err
@@ -498,7 +498,7 @@ func (c *compiler) compileQueryUpdate(l, r *Query, op Operator) error {
}
c.append(&code{op: oppush, v: xs})
c.append(&code{op: opload, v: v})
- c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["setpath"].callback, 2, "setpath"}})
+ c.append(&code{op: opcall, v: [3]any{internalFuncs["setpath"].callback, 2, "setpath"}})
return nil
}
fallthrough
@@ -625,7 +625,7 @@ func (c *compiler) compilePattern(vs [][2]int, p *Pattern) ([][2]int, error) {
c.append(&code{op: opload, v: v})
c.append(&code{op: oppush, v: nil})
// ref: compileCall
- c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}})
+ c.append(&code{op: opcall, v: [3]any{internalFuncs["_index"].callback, 2, "_index"}})
}
if name != "" {
if kv.Val != nil {
@@ -800,12 +800,12 @@ func (c *compiler) compileBreak(label string) error {
}
c.append(&code{op: oppop})
c.append(&code{op: opload, v: v})
- c.append(&code{op: opcall, v: [3]interface{}{funcBreak(label), 0, "_break"}})
+ c.append(&code{op: opcall, v: [3]any{funcBreak(label), 0, "_break"}})
return nil
}
-func funcBreak(label string) func(interface{}, []interface{}) interface{} {
- return func(v interface{}, _ []interface{}) interface{} {
+func funcBreak(label string) func(any, []any) any {
+ return func(v any, _ []any) any {
return &breakError{label, v}
}
}
@@ -907,7 +907,7 @@ func (c *compiler) compileFunc(e *Func) error {
}
return nil
} else if e.Name == "$ENV" || e.Name == "env" {
- env := make(map[string]interface{})
+ env := make(map[string]any)
if c.environLoader != nil {
for _, kv := range c.environLoader() {
if i := strings.IndexByte(kv, '='); i > 0 {
@@ -968,7 +968,7 @@ func (c *compiler) compileFunc(e *Func) error {
return nil
case "builtins":
return c.compileCallInternal(
- [3]interface{}{c.funcBuiltins, 0, e.Name},
+ [3]any{c.funcBuiltins, 0, e.Name},
e.Args,
true,
-1,
@@ -978,14 +978,14 @@ func (c *compiler) compileFunc(e *Func) error {
return &inputNotAllowedError{}
}
return c.compileCallInternal(
- [3]interface{}{c.funcInput, 0, e.Name},
+ [3]any{c.funcInput, 0, e.Name},
e.Args,
true,
-1,
)
case "modulemeta":
return c.compileCallInternal(
- [3]interface{}{c.funcModulemeta, 0, e.Name},
+ [3]any{c.funcModulemeta, 0, e.Name},
e.Args,
true,
-1,
@@ -996,7 +996,7 @@ func (c *compiler) compileFunc(e *Func) error {
}
if fn, ok := c.customFuncs[e.Name]; ok && fn.accept(len(e.Args)) {
if err := c.compileCallInternal(
- [3]interface{}{fn.callback, len(e.Args), e.Name},
+ [3]any{fn.callback, len(e.Args), e.Name},
e.Args,
true,
-1,
@@ -1023,9 +1023,10 @@ func (c *compiler) compileAssign() {
scope := c.newScope()
v, p := [2]int{scope.id, 0}, [2]int{scope.id, 1}
x, a := [2]int{scope.id, 2}, [2]int{scope.id, 3}
- q := [2]int{scope.id, 4} // Cannot reuse p due to backtracking in x.
+ // Cannot reuse v, p due to backtracking in x.
+ w, q := [2]int{scope.id, 4}, [2]int{scope.id, 5}
c.appends(
- &code{op: opscope, v: [3]int{scope.id, 5, 2}},
+ &code{op: opscope, v: [3]int{scope.id, 6, 2}},
&code{op: opstore, v: v}, // def _assign(p; $x):
&code{op: opstore, v: p},
&code{op: opstore, v: x},
@@ -1036,25 +1037,27 @@ func (c *compiler) compileAssign() {
&code{op: opstore, v: x},
&code{op: opexpend},
&code{op: oppush, v: nil},
- &code{op: opcall, v: [3]interface{}{funcAllocator, 0, "_allocator"}},
+ &code{op: opcall, v: [3]any{funcAllocator, 0, "_allocator"}},
&code{op: opstore, v: a},
&code{op: opload, v: v},
- &code{op: opfork, v: len(c.codes) + 28}, // reduce [L1]
- &code{op: oppathbegin}, // path(p)
+ &code{op: opfork, v: len(c.codes) + 30}, // reduce [L1]
+ &code{op: opdup},
+ &code{op: opstore, v: w},
+ &code{op: oppathbegin}, // path(p)
&code{op: opload, v: p},
&code{op: opcallpc},
- &code{op: opload, v: v},
+ &code{op: opload, v: w},
&code{op: oppathend},
&code{op: opstore, v: q}, // as $q (.;
&code{op: opload, v: a}, // setpath($q; $x)
&code{op: opload, v: x},
&code{op: opload, v: q},
- &code{op: opload, v: v},
- &code{op: opcall, v: [3]interface{}{funcSetpathWithAllocator, 3, "_setpath"}},
- &code{op: opstore, v: v},
+ &code{op: opload, v: w},
+ &code{op: opcall, v: [3]any{funcSetpathWithAllocator, 3, "_setpath"}},
+ &code{op: opstore, v: w},
&code{op: opbacktrack}, // );
&code{op: oppop}, // [L1]
- &code{op: opload, v: v},
+ &code{op: opload, v: w},
&code{op: opret},
)
}
@@ -1072,10 +1075,10 @@ func (c *compiler) compileModify() {
&code{op: opstore, v: v}, // def _modify(p; f):
&code{op: opstore, v: p},
&code{op: opstore, v: f},
- &code{op: oppush, v: []interface{}{}},
+ &code{op: oppush, v: []any{}},
&code{op: opstore, v: d},
&code{op: oppush, v: nil},
- &code{op: opcall, v: [3]interface{}{funcAllocator, 0, "_allocator"}},
+ &code{op: opcall, v: [3]any{funcAllocator, 0, "_allocator"}},
&code{op: opstore, v: a},
&code{op: opload, v: v},
&code{op: opfork, v: len(c.codes) + 39}, // reduce [L1]
@@ -1092,18 +1095,18 @@ func (c *compiler) compileModify() {
&code{op: opload, v: a},
&code{op: opload, v: p},
&code{op: opload, v: v},
- &code{op: opcall, v: [3]interface{}{internalFuncs["getpath"].callback, 1, "getpath"}},
+ &code{op: opcall, v: [3]any{internalFuncs["getpath"].callback, 1, "getpath"}},
&code{op: opload, v: f}, // f)
&code{op: opcallpc},
&code{op: opload, v: p}, // setpath($p; ...)
&code{op: opload, v: v},
- &code{op: opcall, v: [3]interface{}{funcSetpathWithAllocator, 3, "_setpath"}},
+ &code{op: opcall, v: [3]any{funcSetpathWithAllocator, 3, "_setpath"}},
&code{op: opstore, v: v},
&code{op: opload, v: v}, // ., break $l
&code{op: opfork, v: len(c.codes) + 34}, // [L4]
&code{op: opjump, v: len(c.codes) + 38}, // [L3]
&code{op: opload, v: l}, // [L4]
- &code{op: opcall, v: [3]interface{}{funcBreak(""), 0, "_break"}},
+ &code{op: opcall, v: [3]any{funcBreak(""), 0, "_break"}},
&code{op: opload, v: p}, // append $p to $d [L2]
&code{op: opappend, v: d}, //
&code{op: opbacktrack}, // ) | [L3]
@@ -1111,12 +1114,12 @@ func (c *compiler) compileModify() {
&code{op: opload, v: a},
&code{op: opload, v: d},
&code{op: opload, v: v},
- &code{op: opcall, v: [3]interface{}{funcDelpathsWithAllocator, 2, "_delpaths"}},
+ &code{op: opcall, v: [3]any{funcDelpathsWithAllocator, 2, "_delpaths"}},
&code{op: opret},
)
}
-func (c *compiler) funcBuiltins(interface{}, []interface{}) interface{} {
+func (c *compiler) funcBuiltins(any, []any) any {
type funcNameArity struct {
name string
arity int
@@ -1151,14 +1154,14 @@ func (c *compiler) funcBuiltins(interface{}, []interface{}) interface{} {
return xs[i].name < xs[j].name ||
xs[i].name == xs[j].name && xs[i].arity < xs[j].arity
})
- ys := make([]interface{}, len(xs))
+ ys := make([]any, len(xs))
for i, x := range xs {
ys[i] = x.name + "/" + strconv.Itoa(x.arity)
}
return ys
}
-func (c *compiler) funcInput(interface{}, []interface{}) interface{} {
+func (c *compiler) funcInput(any, []any) any {
v, ok := c.inputIter.Next()
if !ok {
return errors.New("break")
@@ -1166,10 +1169,10 @@ func (c *compiler) funcInput(interface{}, []interface{}) interface{} {
return normalizeNumbers(v)
}
-func (c *compiler) funcModulemeta(v interface{}, _ []interface{}) interface{} {
+func (c *compiler) funcModulemeta(v any, _ []any) any {
s, ok := v.(string)
if !ok {
- return &funcTypeError{"modulemeta", v}
+ return &func0TypeError{"modulemeta", v}
}
if c.moduleLoader == nil {
return fmt.Errorf("cannot load module: %q", s)
@@ -1177,7 +1180,7 @@ func (c *compiler) funcModulemeta(v interface{}, _ []interface{}) interface{} {
var q *Query
var err error
if moduleLoader, ok := c.moduleLoader.(interface {
- LoadModuleWithMeta(string, map[string]interface{}) (*Query, error)
+ LoadModuleWithMeta(string, map[string]any) (*Query, error)
}); ok {
if q, err = moduleLoader.LoadModuleWithMeta(s, nil); err != nil {
return err
@@ -1191,13 +1194,13 @@ func (c *compiler) funcModulemeta(v interface{}, _ []interface{}) interface{} {
}
meta := q.Meta.ToValue()
if meta == nil {
- meta = make(map[string]interface{})
+ meta = make(map[string]any)
}
- var deps []interface{}
+ deps := []any{}
for _, i := range q.Imports {
v := i.Meta.ToValue()
if v == nil {
- v = make(map[string]interface{})
+ v = make(map[string]any)
} else {
for k := range v {
// dirty hack to remove the internal fields
@@ -1227,7 +1230,7 @@ func (c *compiler) funcModulemeta(v interface{}, _ []interface{}) interface{} {
func (c *compiler) compileObject(e *Object) error {
c.appendCodeInfo(e)
if len(e.KeyVals) == 0 {
- c.append(&code{op: opconst, v: map[string]interface{}{}})
+ c.append(&code{op: opconst, v: map[string]any{}})
return nil
}
defer c.newScopeDepth()()
@@ -1252,7 +1255,7 @@ func (c *compiler) compileObject(e *Object) error {
return nil
}
}
- w := make(map[string]interface{}, l)
+ w := make(map[string]any, l)
for i := 0; i < l; i++ {
w[c.codes[pc+i*3].v.(string)] = c.codes[pc+i*3+2].v
}
@@ -1295,7 +1298,7 @@ func (c *compiler) compileObjectKeyVal(v [2]int, kv *ObjectKeyVal) error {
c.append(&code{op: opload, v: v})
c.append(&code{op: oppush, v: nil})
// ref: compileCall
- c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}})
+ c.append(&code{op: opcall, v: [3]any{internalFuncs["_index"].callback, 2, "_index"}})
}
}
} else if kv.KeyQuery != nil {
@@ -1320,10 +1323,10 @@ func (c *compiler) compileObjectKeyVal(v [2]int, kv *ObjectKeyVal) error {
func (c *compiler) compileArray(e *Array) error {
c.appendCodeInfo(e)
if e.Query == nil {
- c.append(&code{op: opconst, v: []interface{}{}})
+ c.append(&code{op: opconst, v: []any{}})
return nil
}
- c.append(&code{op: oppush, v: []interface{}{}})
+ c.append(&code{op: oppush, v: []any{}})
arr := c.newVariable()
c.append(&code{op: opstore, v: arr})
pc := len(c.codes)
@@ -1354,7 +1357,7 @@ func (c *compiler) compileArray(e *Array) error {
return nil
}
}
- v := make([]interface{}, l)
+ v := make([]any, l)
for i := 0; i < l; i++ {
v[i] = c.codes[pc+i*2+l].v
}
@@ -1382,12 +1385,12 @@ func (c *compiler) compileUnary(e *Unary) error {
}
}
-func (c *compiler) compileFormat(fmt string, str *String) error {
- f := formatToFunc(fmt)
+func (c *compiler) compileFormat(format string, str *String) error {
+ f := formatToFunc(format)
if f == nil {
f = &Func{
Name: "format",
- Args: []*Query{{Term: &Term{Type: TermTypeString, Str: &String{Str: fmt[1:]}}}},
+ Args: []*Query{{Term: &Term{Type: TermTypeString, Str: &String{Str: format[1:]}}}},
}
}
if str == nil {
@@ -1396,8 +1399,8 @@ func (c *compiler) compileFormat(fmt string, str *String) error {
return c.compileString(str, f)
}
-func formatToFunc(fmt string) *Func {
- switch fmt {
+func formatToFunc(format string) *Func {
+ switch format {
case "@text":
return &Func{Name: "tostring"}
case "@json":
@@ -1406,6 +1409,8 @@ func formatToFunc(fmt string) *Func {
return &Func{Name: "_tohtml"}
case "@uri":
return &Func{Name: "_touri"}
+ case "@urid":
+ return &Func{Name: "_tourid"}
case "@csv":
return &Func{Name: "_tocsv"}
case "@tsv":
@@ -1483,7 +1488,7 @@ func (c *compiler) compileCall(name string, args []*Query) error {
indexing = -1
}
if err := c.compileCallInternal(
- [3]interface{}{fn.callback, len(args), name},
+ [3]any{fn.callback, len(args), name},
args,
true,
indexing,
@@ -1501,7 +1506,7 @@ func (c *compiler) compileCallPc(fn *funcinfo, args []*Query) error {
}
func (c *compiler) compileCallInternal(
- fn interface{}, args []*Query, internal bool, indexing int,
+ fn any, args []*Query, internal bool, indexing int,
) error {
if len(args) == 0 {
c.append(&code{op: opcall, v: fn})
diff --git a/compiler_test.go b/compiler_test.go
index d495c7d..d12240a 100644
--- a/compiler_test.go
+++ b/compiler_test.go
@@ -23,12 +23,12 @@ func ExampleCompile() {
if err != nil {
log.Fatalln(err)
}
- iter := code.Run([]interface{}{
+ iter := code.Run([]any{
nil,
"string",
42,
- []interface{}{"foo"},
- map[string]interface{}{"foo": 42},
+ []any{"foo"},
+ map[string]any{"foo": 42},
})
for {
v, ok := iter.Next()
@@ -59,7 +59,7 @@ func ExampleCode_Run() {
if err != nil {
log.Fatalln(err)
}
- input := map[string]interface{}{"foo": 42}
+ input := map[string]any{"foo": 42}
iter := code.Run(input)
for {
v, ok := iter.Next()
@@ -123,8 +123,8 @@ func TestCodeCompile_OptimizeConstants(t *testing.T) {
if !ok {
break
}
- if expected := []interface{}{
- 1, map[string]interface{}{"foo": 2, "bar": 3}, []interface{}{-4},
+ if expected := []any{
+ 1, map[string]any{"foo": 2, "bar": 3}, []any{-4},
}; !reflect.DeepEqual(got, expected) {
t.Errorf("expected: %v, got: %v", expected, got)
}
@@ -175,10 +175,10 @@ func TestCodeCompile_OptimizeIndexSliceAssign(t *testing.T) {
if !ok {
break
}
- if expected := map[string]interface{}{
- "foo": map[string]interface{}{
- "bar": map[string]interface{}{
- "baz": []interface{}{map[string]interface{}{"": []interface{}{0}}},
+ if expected := map[string]any{
+ "foo": map[string]any{
+ "bar": map[string]any{
+ "baz": []any{map[string]any{"": []any{0}}},
},
},
}; !reflect.DeepEqual(got, expected) {
@@ -260,7 +260,7 @@ func TestCodeCompile_OptimizeJumps(t *testing.T) {
t.Errorf("expected: %v, got: %v", expected, got)
}
v := codes.Index(1).Elem().FieldByName("v")
- if got, expected := *(*interface{})(unsafe.Pointer(v.UnsafeAddr())), 13; expected != got {
+ if got, expected := *(*any)(unsafe.Pointer(v.UnsafeAddr())), 13; expected != got {
t.Errorf("expected: %v, got: %v", expected, got)
}
iter := code.Run(nil)
diff --git a/debian/changelog b/debian/changelog
index d0a036f..7c7c697 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+gojq (0.12.13-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Thu, 01 Jun 2023 17:51:50 -0000
+
gojq (0.12.11-1) unstable; urgency=medium
* New upstream version 0.12.11
diff --git a/debug.go b/debug.go
index 2e63908..ad3d721 100644
--- a/debug.go
+++ b/debug.go
@@ -32,7 +32,7 @@ type codeinfo struct {
pc int
}
-func (c *compiler) appendCodeInfo(x interface{}) {
+func (c *compiler) appendCodeInfo(x any) {
if !debug {
return
}
@@ -182,7 +182,7 @@ func debugOperand(c *code) string {
switch v := c.v.(type) {
case int:
return strconv.Itoa(v)
- case [3]interface{}:
+ case [3]any:
return fmt.Sprintf("%s/%d", v[2], v[1])
default:
panic(c)
@@ -192,7 +192,7 @@ func debugOperand(c *code) string {
}
}
-func debugValue(v interface{}) string {
+func debugValue(v any) string {
switch v := v.(type) {
case Iter:
return fmt.Sprintf("gojq.Iter(%#v)", v)
@@ -202,7 +202,7 @@ func debugValue(v interface{}) string {
return fmt.Sprintf("[%d,%d]", v[0], v[1])
case [3]int:
return fmt.Sprintf("[%d,%d,%d]", v[0], v[1], v[2])
- case [3]interface{}:
+ case [3]any:
return fmt.Sprintf("[%v,%v,%v]", v[0], v[1], v[2])
case allocator:
return fmt.Sprintf("%v", v)
diff --git a/encoder.go b/encoder.go
index d61456c..3233e8a 100644
--- a/encoder.go
+++ b/encoder.go
@@ -15,19 +15,19 @@ import (
// Marshal returns the jq-flavored JSON encoding of v.
//
// This method accepts only limited types (nil, bool, int, float64, *big.Int,
-// string, []interface{}, and map[string]interface{}) because these are the
-// possible types a gojq iterator can emit. This method marshals NaN to null,
-// truncates infinities to (+|-) math.MaxFloat64, uses \b and \f in strings,
-// and does not escape '<', '>', '&', '\u2028', and '\u2029'. These behaviors
-// are based on the marshaler of jq command, and different from json.Marshal in
-// the Go standard library. Note that the result is not safe to embed in HTML.
-func Marshal(v interface{}) ([]byte, error) {
+// string, []any, and map[string]any) because these are the possible types a
+// gojq iterator can emit. This method marshals NaN to null, truncates
+// infinities to (+|-) math.MaxFloat64, uses \b and \f in strings, and does not
+// escape '<', '>', '&', '\u2028', and '\u2029'. These behaviors are based on
+// the marshaler of jq command, and different from json.Marshal in the Go
+// standard library. Note that the result is not safe to embed in HTML.
+func Marshal(v any) ([]byte, error) {
var b bytes.Buffer
(&encoder{w: &b}).encode(v)
return b.Bytes(), nil
}
-func jsonMarshal(v interface{}) string {
+func jsonMarshal(v any) string {
var sb strings.Builder
(&encoder{w: &sb}).encode(v)
return sb.String()
@@ -46,7 +46,7 @@ type encoder struct {
buf [64]byte
}
-func (e *encoder) encode(v interface{}) {
+func (e *encoder) encode(v any) {
switch v := v.(type) {
case nil:
e.w.WriteString("null")
@@ -64,10 +64,10 @@ func (e *encoder) encode(v interface{}) {
e.w.Write(v.Append(e.buf[:0], 10))
case string:
e.encodeString(v)
- case []interface{}:
+ case []any:
e.encodeArray(v)
- case map[string]interface{}:
- e.encodeMap(v)
+ case map[string]any:
+ e.encodeObject(v)
default:
panic(fmt.Sprintf("invalid type: %[1]T (%[1]v)", v))
}
@@ -84,12 +84,12 @@ func (e *encoder) encodeFloat64(f float64) {
} else if f <= -math.MaxFloat64 {
f = -math.MaxFloat64
}
- fmt := byte('f')
+ format := byte('f')
if x := math.Abs(f); x != 0 && x < 1e-6 || x >= 1e21 {
- fmt = 'e'
+ format = 'e'
}
- buf := strconv.AppendFloat(e.buf[:0], f, fmt, -1, 64)
- if fmt == 'e' {
+ buf := strconv.AppendFloat(e.buf[:0], f, format, -1, 64)
+ if format == 'e' {
// clean up e-09 to e-9
if n := len(buf); n >= 4 && buf[n-4] == 'e' && buf[n-3] == '-' && buf[n-2] == '0' {
buf[n-2] = buf[n-1]
@@ -155,7 +155,7 @@ func (e *encoder) encodeString(s string) {
e.w.WriteByte('"')
}
-func (e *encoder) encodeArray(vs []interface{}) {
+func (e *encoder) encodeArray(vs []any) {
e.w.WriteByte('[')
for i, v := range vs {
if i > 0 {
@@ -166,11 +166,11 @@ func (e *encoder) encodeArray(vs []interface{}) {
e.w.WriteByte(']')
}
-func (e *encoder) encodeMap(vs map[string]interface{}) {
+func (e *encoder) encodeObject(vs map[string]any) {
e.w.WriteByte('{')
type keyVal struct {
key string
- val interface{}
+ val any
}
kvs := make([]keyVal, len(vs))
var i int
diff --git a/encoder_test.go b/encoder_test.go
index 5d9d2b7..1d1247e 100644
--- a/encoder_test.go
+++ b/encoder_test.go
@@ -11,7 +11,7 @@ import (
func TestMarshal(t *testing.T) {
testCases := []struct {
- value interface{}
+ value any
expected string
}{
{
@@ -19,26 +19,26 @@ func TestMarshal(t *testing.T) {
expected: "null",
},
{
- value: []interface{}{false, true},
+ value: []any{false, true},
expected: "[false,true]",
},
{
- value: []interface{}{
+ value: []any{
42, 3.14, 1e-6, 1e-7, -1e-9, 1e-10, math.NaN(), math.Inf(1), math.Inf(-1),
new(big.Int).SetBytes([]byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff")),
},
expected: "[42,3.14,0.000001,1e-7,-1e-9,1e-10,null,1.7976931348623157e+308,-1.7976931348623157e+308,340282366920938463463374607431768211455]",
},
{
- value: []interface{}{"", "abcde", "foo\x00\x1f\r\n\t\f\b<=>!\"#$%'& \\\x7fbar"},
+ value: []any{"", "abcde", "foo\x00\x1f\r\n\t\f\b<=>!\"#$%'& \\\x7fbar"},
expected: `["","abcde","foo\u0000\u001f\r\n\t\f\b<=>!\"#$%'& \\\u007fbar"]`,
},
{
- value: []interface{}{1, []interface{}{2, []interface{}{3, []interface{}{map[string]interface{}{}}}}},
+ value: []any{1, []any{2, []any{3, []any{map[string]any{}}}}},
expected: `[1,[2,[3,[{}]]]]`,
},
{
- value: map[string]interface{}{"x": []interface{}{100}, "y": map[string]interface{}{"z": 42}},
+ value: map[string]any{"x": []any{100}, "y": map[string]any{"z": 42}},
expected: `{"x":[100],"y":{"z":42}}`,
},
}
diff --git a/env.go b/env.go
index dd1859c..bf058ed 100644
--- a/env.go
+++ b/env.go
@@ -7,7 +7,7 @@ type env struct {
stack *stack
paths *stack
scopes *scopeStack
- values []interface{}
+ values []any
codes []*code
codeinfos []codeinfo
forks []fork
@@ -15,7 +15,7 @@ type env struct {
offset int
expdepth int
label int
- args [32]interface{} // len(env.args) > maxarity
+ args [32]any // len(env.args) > maxarity
ctx context.Context
}
diff --git a/error.go b/error.go
index e128b54..1686587 100644
--- a/error.go
+++ b/error.go
@@ -8,11 +8,11 @@ import "strconv"
// Refer to [WithFunction] to add a custom internal function.
type ValueError interface {
error
- Value() interface{}
+ Value() any
}
type expectedObjectError struct {
- v interface{}
+ v any
}
func (err *expectedObjectError) Error() string {
@@ -20,31 +20,31 @@ func (err *expectedObjectError) Error() string {
}
type expectedArrayError struct {
- v interface{}
+ v any
}
func (err *expectedArrayError) Error() string {
return "expected an array but got: " + typeErrorPreview(err.v)
}
-type expectedStringError struct {
- v interface{}
+type iteratorError struct {
+ v any
}
-func (err *expectedStringError) Error() string {
- return "expected a string but got: " + typeErrorPreview(err.v)
+func (err *iteratorError) Error() string {
+ return "cannot iterate over: " + typeErrorPreview(err.v)
}
-type iteratorError struct {
- v interface{}
+type arrayIndexNegativeError struct {
+ v int
}
-func (err *iteratorError) Error() string {
- return "cannot iterate over: " + typeErrorPreview(err.v)
+func (err *arrayIndexNegativeError) Error() string {
+ return "array index should not be negative: " + Preview(err.v)
}
type arrayIndexTooLargeError struct {
- v interface{}
+ v any
}
func (err *arrayIndexTooLargeError) Error() string {
@@ -52,7 +52,7 @@ func (err *arrayIndexTooLargeError) Error() string {
}
type objectKeyNotStringError struct {
- v interface{}
+ v any
}
func (err *objectKeyNotStringError) Error() string {
@@ -60,7 +60,7 @@ func (err *objectKeyNotStringError) Error() string {
}
type arrayIndexNotNumberError struct {
- v interface{}
+ v any
}
func (err *arrayIndexNotNumberError) Error() string {
@@ -68,7 +68,7 @@ func (err *arrayIndexNotNumberError) Error() string {
}
type stringIndexNotNumberError struct {
- v interface{}
+ v any
}
func (err *stringIndexNotNumberError) Error() string {
@@ -76,20 +76,17 @@ func (err *stringIndexNotNumberError) Error() string {
}
type expectedStartEndError struct {
- v interface{}
+ v any
}
func (err *expectedStartEndError) Error() string {
return `expected "start" and "end" for slicing but got: ` + typeErrorPreview(err.v)
}
-type lengthMismatchError struct {
- name string
- v, x []interface{}
-}
+type lengthMismatchError struct{}
func (err *lengthMismatchError) Error() string {
- return "length mismatch in " + err.name + ": " + typeErrorPreview(err.v) + ", " + typeErrorPreview(err.x)
+ return "length mismatch"
}
type inputNotAllowedError struct{}
@@ -106,17 +103,65 @@ func (err *funcNotFoundError) Error() string {
return "function not defined: " + err.f.Name + "/" + strconv.Itoa(len(err.f.Args))
}
-type funcTypeError struct {
+type func0TypeError struct {
name string
- v interface{}
+ v any
}
-func (err *funcTypeError) Error() string {
+func (err *func0TypeError) Error() string {
return err.name + " cannot be applied to: " + typeErrorPreview(err.v)
}
+type func1TypeError struct {
+ name string
+ v, w any
+}
+
+func (err *func1TypeError) Error() string {
+ return err.name + "(" + Preview(err.w) + ") cannot be applied to: " + typeErrorPreview(err.v)
+}
+
+type func2TypeError struct {
+ name string
+ v, w, x any
+}
+
+func (err *func2TypeError) Error() string {
+ return err.name + "(" + Preview(err.w) + "; " + Preview(err.x) + ") cannot be applied to: " + typeErrorPreview(err.v)
+}
+
+type func0WrapError struct {
+ name string
+ v any
+ err error
+}
+
+func (err *func0WrapError) Error() string {
+ return err.name + " cannot be applied to " + Preview(err.v) + ": " + err.err.Error()
+}
+
+type func1WrapError struct {
+ name string
+ v, w any
+ err error
+}
+
+func (err *func1WrapError) Error() string {
+ return err.name + "(" + Preview(err.w) + ") cannot be applied to " + Preview(err.v) + ": " + err.err.Error()
+}
+
+type func2WrapError struct {
+ name string
+ v, w, x any
+ err error
+}
+
+func (err *func2WrapError) Error() string {
+ return err.name + "(" + Preview(err.w) + "; " + Preview(err.x) + ") cannot be applied to " + Preview(err.v) + ": " + err.err.Error()
+}
+
type exitCodeError struct {
- value interface{}
+ value any
code int
halt bool
}
@@ -132,7 +177,7 @@ func (err *exitCodeError) IsEmptyError() bool {
return err.value == nil
}
-func (err *exitCodeError) Value() interface{} {
+func (err *exitCodeError) Value() any {
return err.value
}
@@ -144,41 +189,31 @@ func (err *exitCodeError) IsHaltError() bool {
return err.halt
}
-type containsTypeError struct {
- l, r interface{}
-}
-
-func (err *containsTypeError) Error() string {
- return "cannot check contains(" + Preview(err.r) + "): " + typeErrorPreview(err.l)
-}
-
-type hasKeyTypeError struct {
- l, r interface{}
-}
-
-func (err *hasKeyTypeError) Error() string {
- return "cannot check whether " + typeErrorPreview(err.l) + " has a key: " + typeErrorPreview(err.r)
-}
-
type flattenDepthError struct {
v float64
}
func (err *flattenDepthError) Error() string {
- return "flatten depth must not be negative: " + typeErrorPreview(err.v)
+ return "flatten depth should not be negative: " + Preview(err.v)
}
type joinTypeError struct {
- v interface{}
+ v any
}
func (err *joinTypeError) Error() string {
- return "cannot join: " + typeErrorPreview(err.v)
+ return "join cannot be applied to an array including: " + typeErrorPreview(err.v)
+}
+
+type timeArrayError struct{}
+
+func (err *timeArrayError) Error() string {
+ return "expected an array of 8 numbers"
}
type unaryTypeError struct {
name string
- v interface{}
+ v any
}
func (err *unaryTypeError) Error() string {
@@ -187,7 +222,7 @@ func (err *unaryTypeError) Error() string {
type binopTypeError struct {
name string
- l, r interface{}
+ l, r any
}
func (err *binopTypeError) Error() string {
@@ -195,7 +230,7 @@ func (err *binopTypeError) Error() string {
}
type zeroDivisionError struct {
- l, r interface{}
+ l, r any
}
func (err *zeroDivisionError) Error() string {
@@ -203,7 +238,7 @@ func (err *zeroDivisionError) Error() string {
}
type zeroModuloError struct {
- l, r interface{}
+ l, r any
}
func (err *zeroModuloError) Error() string {
@@ -220,7 +255,7 @@ func (err *formatNotFoundError) Error() string {
type formatRowError struct {
typ string
- v interface{}
+ v any
}
func (err *formatRowError) Error() string {
@@ -259,7 +294,7 @@ func (err *variableNameError) Error() string {
type breakError struct {
n string
- v interface{}
+ v any
}
func (err *breakError) Error() string {
@@ -279,7 +314,7 @@ func (err *tryEndError) Error() string {
}
type invalidPathError struct {
- v interface{}
+ v any
}
func (err *invalidPathError) Error() string {
@@ -287,21 +322,13 @@ func (err *invalidPathError) Error() string {
}
type invalidPathIterError struct {
- v interface{}
+ v any
}
func (err *invalidPathIterError) Error() string {
return "invalid path on iterating against: " + typeErrorPreview(err.v)
}
-type getpathError struct {
- v, path interface{}
-}
-
-func (err *getpathError) Error() string {
- return "cannot getpath with " + Preview(err.path) + " against: " + typeErrorPreview(err.v)
-}
-
type queryParseError struct {
fname, contents string
err error
@@ -328,7 +355,7 @@ func (err *jsonParseError) Error() string {
return "invalid json: " + err.fname + ": " + err.err.Error()
}
-func typeErrorPreview(v interface{}) string {
+func typeErrorPreview(v any) string {
switch v.(type) {
case nil:
return "null"
diff --git a/execute.go b/execute.go
index af00229..dcf9d98 100644
--- a/execute.go
+++ b/execute.go
@@ -7,7 +7,7 @@ import (
"sort"
)
-func (env *env) execute(bc *Code, v interface{}, vars ...interface{}) Iter {
+func (env *env) execute(bc *Code, v any, vars ...any) Iter {
env.codes = bc.codes
env.codeinfos = bc.codeinfos
env.push(v)
@@ -18,7 +18,7 @@ func (env *env) execute(bc *Code, v interface{}, vars ...interface{}) Iter {
return env
}
-func (env *env) Next() (interface{}, bool) {
+func (env *env) Next() (any, bool) {
var err error
pc, callpc, index := env.pc, len(env.codes)-1, -1
backtrack, hasCtx := env.backtrack, env.ctx != context.Background()
@@ -58,7 +58,7 @@ loop:
break loop
}
n := code.v.(int)
- m := make(map[string]interface{}, n)
+ m := make(map[string]any, n)
for i := 0; i < n; i++ {
v, k := env.pop(), env.pop()
s, ok := k.(string)
@@ -71,7 +71,7 @@ loop:
env.push(m)
case opappend:
i := env.index(code.v.([2]int))
- env.values[i] = append(env.values[i].([]interface{}), env.pop())
+ env.values[i] = append(env.values[i].([]any), env.pop())
case opfork:
if backtrack {
if err != nil {
@@ -157,7 +157,7 @@ loop:
}
p, v := code.v, env.pop()
if code.op == opindexarray && v != nil {
- if _, ok := v.([]interface{}); !ok {
+ if _, ok := v.([]any); !ok {
err = &expectedArrayError{v}
break loop
}
@@ -183,13 +183,13 @@ loop:
case int:
pc, callpc, index = v, pc, env.scopes.index
goto loop
- case [3]interface{}:
+ case [3]any:
argcnt := v[1].(int)
x, args := env.pop(), env.args[:argcnt]
for i := 0; i < argcnt; i++ {
args[i] = env.pop()
}
- w := v[0].(func(interface{}, []interface{}) interface{})(x, args)
+ w := v[0].(func(any, []any) any)(x, args)
if e, ok := w.(error); ok {
if er, ok := e.(*exitCodeError); !ok || er.value != nil || er.halt {
err = e
@@ -211,7 +211,7 @@ loop:
break loop
}
env.paths.push(pathValue{
- path: map[string]interface{}{"start": args[2], "end": args[1]},
+ path: map[string]any{"start": args[2], "end": args[1]},
value: w,
})
case "getpath":
@@ -219,7 +219,7 @@ loop:
err = &invalidPathError{x}
break loop
}
- for _, p := range args[0].([]interface{}) {
+ for _, p := range args[0].([]any) {
env.paths.push(pathValue{path: p, value: w})
}
}
@@ -257,7 +257,7 @@ loop:
env.scopes.push(scope{xs[0], env.offset, callpc, saveindex, outerindex})
env.offset += xs[1]
if env.offset > len(env.values) {
- vs := make([]interface{}, env.offset*2)
+ vs := make([]any, env.offset*2)
copy(vs, env.values)
env.values = vs
}
@@ -278,7 +278,7 @@ loop:
switch v := env.pop().(type) {
case []pathValue:
xs = v
- case []interface{}:
+ case []any:
if !env.paths.empty() && env.expdepth == 0 && !env.pathIntact(v) {
err = &invalidPathIterError{v}
break loop
@@ -290,7 +290,7 @@ loop:
for i, v := range v {
xs[i] = pathValue{path: i, value: v}
}
- case map[string]interface{}:
+ case map[string]any:
if !env.paths.empty() && env.expdepth == 0 && !env.pathIntact(v) {
err = &invalidPathIterError{v}
break loop
@@ -367,11 +367,11 @@ loop:
return nil, false
}
-func (env *env) push(v interface{}) {
+func (env *env) push(v any) {
env.stack.push(v)
}
-func (env *env) pop() interface{} {
+func (env *env) pop() any {
return env.stack.pop()
}
@@ -415,15 +415,15 @@ func (env *env) index(v [2]int) int {
}
type pathValue struct {
- path, value interface{}
+ path, value any
}
-func (env *env) pathIntact(v interface{}) bool {
+func (env *env) pathIntact(v any) bool {
w := env.paths.top().(pathValue).value
switch v := v.(type) {
- case []interface{}, map[string]interface{}:
+ case []any, map[string]any:
switch w.(type) {
- case []interface{}, map[string]interface{}:
+ case []any, map[string]any:
v, w := reflect.ValueOf(v), reflect.ValueOf(w)
return v.Pointer() == w.Pointer() && v.Len() == w.Len()
}
@@ -435,8 +435,8 @@ func (env *env) pathIntact(v interface{}) bool {
return v == w
}
-func (env *env) poppaths() []interface{} {
- var xs []interface{}
+func (env *env) poppaths() []any {
+ xs := []any{}
for {
p := env.paths.pop().(pathValue)
if p.path == nil {
diff --git a/func.go b/func.go
index 2c2a28f..6e8d150 100644
--- a/func.go
+++ b/func.go
@@ -3,6 +3,7 @@ package gojq
import (
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"io"
"math"
@@ -32,7 +33,7 @@ const (
type function struct {
argcount int
iter bool
- callback func(interface{}, []interface{}) interface{}
+ callback func(any, []any) any
}
func (fn function) accept(cnt int) bool {
@@ -78,6 +79,7 @@ func init() {
"format": argFunc1(funcFormat),
"_tohtml": argFunc0(funcToHTML),
"_touri": argFunc0(funcToURI),
+ "_tourid": argFunc0(funcToURId),
"_tocsv": argFunc0(funcToCSV),
"_totsv": argFunc0(funcToTSV),
"_tosh": argFunc0(funcToSh),
@@ -198,81 +200,81 @@ func init() {
}
}
-func argFunc0(f func(interface{}) interface{}) function {
+func argFunc0(f func(any) any) function {
return function{
- argcount0, false, func(v interface{}, _ []interface{}) interface{} {
+ argcount0, false, func(v any, _ []any) any {
return f(v)
},
}
}
-func argFunc1(f func(_, _ interface{}) interface{}) function {
+func argFunc1(f func(_, _ any) any) function {
return function{
- argcount1, false, func(v interface{}, args []interface{}) interface{} {
+ argcount1, false, func(v any, args []any) any {
return f(v, args[0])
},
}
}
-func argFunc2(f func(_, _, _ interface{}) interface{}) function {
+func argFunc2(f func(_, _, _ any) any) function {
return function{
- argcount2, false, func(v interface{}, args []interface{}) interface{} {
+ argcount2, false, func(v any, args []any) any {
return f(v, args[0], args[1])
},
}
}
-func argFunc3(f func(_, _, _, _ interface{}) interface{}) function {
+func argFunc3(f func(_, _, _, _ any) any) function {
return function{
- argcount3, false, func(v interface{}, args []interface{}) interface{} {
+ argcount3, false, func(v any, args []any) any {
return f(v, args[0], args[1], args[2])
},
}
}
func mathFunc(name string, f func(float64) float64) function {
- return argFunc0(func(v interface{}) interface{} {
+ return argFunc0(func(v any) any {
x, ok := toFloat(v)
if !ok {
- return &funcTypeError{name, v}
+ return &func0TypeError{name, v}
}
return f(x)
})
}
func mathFunc2(name string, f func(_, _ float64) float64) function {
- return argFunc2(func(_, x, y interface{}) interface{} {
+ return argFunc2(func(_, x, y any) any {
l, ok := toFloat(x)
if !ok {
- return &funcTypeError{name, x}
+ return &func0TypeError{name, x}
}
r, ok := toFloat(y)
if !ok {
- return &funcTypeError{name, y}
+ return &func0TypeError{name, y}
}
return f(l, r)
})
}
func mathFunc3(name string, f func(_, _, _ float64) float64) function {
- return argFunc3(func(_, a, b, c interface{}) interface{} {
+ return argFunc3(func(_, a, b, c any) any {
x, ok := toFloat(a)
if !ok {
- return &funcTypeError{name, a}
+ return &func0TypeError{name, a}
}
y, ok := toFloat(b)
if !ok {
- return &funcTypeError{name, b}
+ return &func0TypeError{name, b}
}
z, ok := toFloat(c)
if !ok {
- return &funcTypeError{name, c}
+ return &func0TypeError{name, c}
}
return f(x, y, z)
})
}
-func funcLength(v interface{}) interface{} {
+func funcLength(v any) any {
switch v := v.(type) {
case nil:
return 0
@@ -290,43 +292,43 @@ func funcLength(v interface{}) interface{} {
return new(big.Int).Abs(v)
case string:
return len([]rune(v))
- case []interface{}:
+ case []any:
return len(v)
- case map[string]interface{}:
+ case map[string]any:
return len(v)
default:
- return &funcTypeError{"length", v}
+ return &func0TypeError{"length", v}
}
}
-func funcUtf8ByteLength(v interface{}) interface{} {
+func funcUtf8ByteLength(v any) any {
s, ok := v.(string)
if !ok {
- return &funcTypeError{"utf8bytelength", v}
+ return &func0TypeError{"utf8bytelength", v}
}
return len(s)
}
-func funcKeys(v interface{}) interface{} {
+func funcKeys(v any) any {
switch v := v.(type) {
- case []interface{}:
- w := make([]interface{}, len(v))
+ case []any:
+ w := make([]any, len(v))
for i := range v {
w[i] = i
}
return w
- case map[string]interface{}:
- w := make([]interface{}, len(v))
+ case map[string]any:
+ w := make([]any, len(v))
for i, k := range keys(v) {
w[i] = k
}
return w
default:
- return &funcTypeError{"keys", v}
+ return &func0TypeError{"keys", v}
}
}
-func keys(v map[string]interface{}) []string {
+func keys(v map[string]any) []string {
w := make([]string, len(v))
var i int
for k := range v {
@@ -337,12 +339,12 @@ func keys(v map[string]interface{}) []string {
return w
}
-func values(v interface{}) ([]interface{}, bool) {
+func values(v any) ([]any, bool) {
switch v := v.(type) {
- case []interface{}:
+ case []any:
return v, true
- case map[string]interface{}:
- vs := make([]interface{}, len(v))
+ case map[string]any:
+ vs := make([]any, len(v))
for i, k := range keys(v) {
vs[i] = v[k]
}
@@ -352,13 +354,13 @@ func values(v interface{}) ([]interface{}, bool) {
}
}
-func funcHas(v, x interface{}) interface{} {
+func funcHas(v, x any) any {
switch v := v.(type) {
- case []interface{}:
+ case []any:
if x, ok := toInt(x); ok {
return 0 <= x && x < len(v)
}
- case map[string]interface{}:
+ case map[string]any:
if x, ok := x.(string); ok {
_, ok := v[x]
return ok
@@ -366,52 +368,52 @@ func funcHas(v, x interface{}) interface{} {
case nil:
return false
}
- return &hasKeyTypeError{v, x}
+ return &func1TypeError{"has", v, x}
}
-func funcToEntries(v interface{}) interface{} {
+func funcToEntries(v any) any {
switch v := v.(type) {
- case []interface{}:
- w := make([]interface{}, len(v))
+ case []any:
+ w := make([]any, len(v))
for i, x := range v {
- w[i] = map[string]interface{}{"key": i, "value": x}
+ w[i] = map[string]any{"key": i, "value": x}
}
return w
- case map[string]interface{}:
- w := make([]interface{}, len(v))
+ case map[string]any:
+ w := make([]any, len(v))
for i, k := range keys(v) {
- w[i] = map[string]interface{}{"key": k, "value": v[k]}
+ w[i] = map[string]any{"key": k, "value": v[k]}
}
return w
default:
- return &funcTypeError{"to_entries", v}
+ return &func0TypeError{"to_entries", v}
}
}
-func funcFromEntries(v interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcFromEntries(v any) any {
+ vs, ok := v.([]any)
if !ok {
- return &funcTypeError{"from_entries", v}
+ return &func0TypeError{"from_entries", v}
}
- w := make(map[string]interface{}, len(vs))
+ w := make(map[string]any, len(vs))
for _, v := range vs {
switch v := v.(type) {
- case map[string]interface{}:
+ case map[string]any:
var (
key string
- value interface{}
+ value any
ok bool
)
for _, k := range [4]string{"key", "Key", "name", "Name"} {
if k := v[k]; k != nil && k != false {
if key, ok = k.(string); !ok {
- return &objectKeyNotStringError{k}
+ return &func0WrapError{"from_entries", vs, &objectKeyNotStringError{k}}
}
break
}
}
if !ok {
- return &objectKeyNotStringError{nil}
+ return &func0WrapError{"from_entries", vs, &objectKeyNotStringError{nil}}
}
for _, k := range [2]string{"value", "Value"} {
if value, ok = v[k]; ok {
@@ -420,16 +422,16 @@ func funcFromEntries(v interface{}) interface{} {
}
w[key] = value
default:
- return &funcTypeError{"from_entries", v}
+ return &func0TypeError{"from_entries", v}
}
}
return w
}
-func funcAdd(v interface{}) interface{} {
+func funcAdd(v any) any {
vs, ok := values(v)
if !ok {
- return &funcTypeError{"add", v}
+ return &func0TypeError{"add", v}
}
v = nil
for _, x := range vs {
@@ -447,27 +449,27 @@ func funcAdd(v interface{}) interface{} {
w.WriteString(x)
continue
}
- case []interface{}:
+ case []any:
switch w := v.(type) {
case nil:
- s := make([]interface{}, len(x))
+ s := make([]any, len(x))
copy(s, x)
v = s
continue
- case []interface{}:
+ case []any:
v = append(w, x...)
continue
}
- case map[string]interface{}:
+ case map[string]any:
switch w := v.(type) {
case nil:
- m := make(map[string]interface{}, len(x))
+ m := make(map[string]any, len(x))
for k, e := range x {
m[k] = e
}
v = m
continue
- case map[string]interface{}:
+ case map[string]any:
for k, e := range x {
w[k] = e
}
@@ -488,54 +490,54 @@ func funcAdd(v interface{}) interface{} {
return v
}
-func funcToNumber(v interface{}) interface{} {
+func funcToNumber(v any) any {
switch v := v.(type) {
case int, float64, *big.Int:
return v
case string:
if !newLexer(v).validNumber() {
- return fmt.Errorf("invalid number: %q", v)
+ return &func0WrapError{"tonumber", v, errors.New("invalid number")}
}
return toNumber(v)
default:
- return &funcTypeError{"tonumber", v}
+ return &func0TypeError{"tonumber", v}
}
}
-func toNumber(v string) interface{} {
+func toNumber(v string) any {
return normalizeNumber(json.Number(v))
}
-func funcToString(v interface{}) interface{} {
+func funcToString(v any) any {
if s, ok := v.(string); ok {
return s
}
return funcToJSON(v)
}
-func funcType(v interface{}) interface{} {
+func funcType(v any) any {
return TypeOf(v)
}
-func funcReverse(v interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcReverse(v any) any {
+ vs, ok := v.([]any)
if !ok {
- return &funcTypeError{"reverse", v}
+ return &func0TypeError{"reverse", v}
}
- ws := make([]interface{}, len(vs))
+ ws := make([]any, len(vs))
for i, v := range vs {
ws[len(ws)-i-1] = v
}
return ws
}
-func funcContains(v, x interface{}) interface{} {
+func funcContains(v, x any) any {
return binopTypeSwitch(v, x,
- func(l, r int) interface{} { return l == r },
- func(l, r float64) interface{} { return l == r },
- func(l, r *big.Int) interface{} { return l.Cmp(r) == 0 },
- func(l, r string) interface{} { return strings.Contains(l, r) },
- func(l, r []interface{}) interface{} {
+ func(l, r int) any { return l == r },
+ func(l, r float64) any { return l == r },
+ func(l, r *big.Int) any { return l.Cmp(r) == 0 },
+ func(l, r string) any { return strings.Contains(l, r) },
+ func(l, r []any) any {
R:
for _, r := range r {
for _, l := range l {
@@ -547,7 +549,7 @@ func funcContains(v, x interface{}) interface{} {
}
return true
},
- func(l, r map[string]interface{}) interface{} {
+ func(l, r map[string]any) any {
if len(l) < len(r) {
return false
}
@@ -558,21 +560,21 @@ func funcContains(v, x interface{}) interface{} {
}
return true
},
- func(l, r interface{}) interface{} {
+ func(l, r any) any {
if l == r {
return true
}
- return &containsTypeError{l, r}
+ return &func1TypeError{"contains", l, r}
},
)
}
-func funcIndices(v, x interface{}) interface{} {
- return indexFunc(v, x, indices)
+func funcIndices(v, x any) any {
+ return indexFunc("indices", v, x, indices)
}
-func indices(vs, xs []interface{}) interface{} {
- var rs []interface{}
+func indices(vs, xs []any) any {
+ rs := []any{}
if len(xs) == 0 {
return rs
}
@@ -584,8 +586,8 @@ func indices(vs, xs []interface{}) interface{} {
return rs
}
-func funcIndex(v, x interface{}) interface{} {
- return indexFunc(v, x, func(vs, xs []interface{}) interface{} {
+func funcIndex(v, x any) any {
+ return indexFunc("index", v, x, func(vs, xs []any) any {
if len(xs) == 0 {
return nil
}
@@ -598,8 +600,8 @@ func funcIndex(v, x interface{}) interface{} {
})
}
-func funcRindex(v, x interface{}) interface{} {
- return indexFunc(v, x, func(vs, xs []interface{}) interface{} {
+func funcRindex(v, x any) any {
+ return indexFunc("rindex", v, x, func(vs, xs []any) any {
if len(xs) == 0 {
return nil
}
@@ -612,52 +614,52 @@ func funcRindex(v, x interface{}) interface{} {
})
}
-func indexFunc(v, x interface{}, f func(_, _ []interface{}) interface{}) interface{} {
+func indexFunc(name string, v, x any, f func(_, _ []any) any) any {
switch v := v.(type) {
case nil:
return nil
- case []interface{}:
+ case []any:
switch x := x.(type) {
- case []interface{}:
+ case []any:
return f(v, x)
default:
- return f(v, []interface{}{x})
+ return f(v, []any{x})
}
case string:
if x, ok := x.(string); ok {
return f(explode(v), explode(x))
}
- return &expectedStringError{x}
+ return &func1TypeError{name, v, x}
default:
- return &expectedArrayError{v}
+ return &func1TypeError{name, v, x}
}
}
-func funcStartsWith(v, x interface{}) interface{} {
+func funcStartsWith(v, x any) any {
s, ok := v.(string)
if !ok {
- return &funcTypeError{"startswith", v}
+ return &func1TypeError{"startswith", v, x}
}
t, ok := x.(string)
if !ok {
- return &funcTypeError{"startswith", x}
+ return &func1TypeError{"startswith", v, x}
}
return strings.HasPrefix(s, t)
}
-func funcEndsWith(v, x interface{}) interface{} {
+func funcEndsWith(v, x any) any {
s, ok := v.(string)
if !ok {
- return &funcTypeError{"endswith", v}
+ return &func1TypeError{"endswith", v, x}
}
t, ok := x.(string)
if !ok {
- return &funcTypeError{"endswith", x}
+ return &func1TypeError{"endswith", v, x}
}
return strings.HasSuffix(s, t)
}
-func funcLtrimstr(v, x interface{}) interface{} {
+func funcLtrimstr(v, x any) any {
s, ok := v.(string)
if !ok {
return v
@@ -669,7 +671,7 @@ func funcLtrimstr(v, x interface{}) interface{} {
return strings.TrimPrefix(s, t)
}
-func funcRtrimstr(v, x interface{}) interface{} {
+func funcRtrimstr(v, x any) any {
s, ok := v.(string)
if !ok {
return v
@@ -681,16 +683,16 @@ func funcRtrimstr(v, x interface{}) interface{} {
return strings.TrimSuffix(s, t)
}
-func funcExplode(v interface{}) interface{} {
+func funcExplode(v any) any {
s, ok := v.(string)
if !ok {
- return &funcTypeError{"explode", v}
+ return &func0TypeError{"explode", v}
}
return explode(s)
}
-func explode(s string) []interface{} {
- xs := make([]interface{}, len([]rune(s)))
+func explode(s string) []any {
+ xs := make([]any, len([]rune(s)))
var i int
for _, r := range s {
xs[i] = int(r)
@@ -699,10 +701,10 @@ func explode(s string) []interface{} {
return xs
}
-func funcImplode(v interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcImplode(v any) any {
+ vs, ok := v.([]any)
if !ok {
- return &funcTypeError{"implode", v}
+ return &func0TypeError{"implode", v}
}
var sb strings.Builder
sb.Grow(len(vs))
@@ -710,20 +712,20 @@ func funcImplode(v interface{}) interface{} {
if r, ok := toInt(v); ok && 0 <= r && r <= utf8.MaxRune {
sb.WriteRune(rune(r))
} else {
- return &funcTypeError{"implode", vs}
+ return &func0TypeError{"implode", vs}
}
}
return sb.String()
}
-func funcSplit(v interface{}, args []interface{}) interface{} {
+func funcSplit(v any, args []any) any {
s, ok := v.(string)
if !ok {
- return &funcTypeError{"split", v}
+ return &func0TypeError{"split", v}
}
x, ok := args[0].(string)
if !ok {
- return &funcTypeError{"split", x}
+ return &func0TypeError{"split", x}
}
var ss []string
if len(args) == 1 {
@@ -733,7 +735,7 @@ func funcSplit(v interface{}, args []interface{}) interface{} {
if args[1] != nil {
v, ok := args[1].(string)
if !ok {
- return &funcTypeError{"split", args[1]}
+ return &func0TypeError{"split", args[1]}
}
flags = v
}
@@ -743,17 +745,17 @@ func funcSplit(v interface{}, args []interface{}) interface{} {
}
ss = r.Split(s, -1)
}
- xs := make([]interface{}, len(ss))
+ xs := make([]any, len(ss))
for i, s := range ss {
xs[i] = s
}
return xs
}
-func funcASCIIDowncase(v interface{}) interface{} {
+func funcASCIIDowncase(v any) any {
s, ok := v.(string)
if !ok {
- return &funcTypeError{"ascii_downcase", v}
+ return &func0TypeError{"ascii_downcase", v}
}
return strings.Map(func(r rune) rune {
if 'A' <= r && r <= 'Z' {
@@ -763,10 +765,10 @@ func funcASCIIDowncase(v interface{}) interface{} {
}, s)
}
-func funcASCIIUpcase(v interface{}) interface{} {
+func funcASCIIUpcase(v any) any {
s, ok := v.(string)
if !ok {
- return &funcTypeError{"ascii_upcase", v}
+ return &func0TypeError{"ascii_upcase", v}
}
return strings.Map(func(r rune) rune {
if 'a' <= r && r <= 'z' {
@@ -776,36 +778,36 @@ func funcASCIIUpcase(v interface{}) interface{} {
}, s)
}
-func funcToJSON(v interface{}) interface{} {
+func funcToJSON(v any) any {
return jsonMarshal(v)
}
-func funcFromJSON(v interface{}) interface{} {
+func funcFromJSON(v any) any {
s, ok := v.(string)
if !ok {
- return &funcTypeError{"fromjson", v}
+ return &func0TypeError{"fromjson", v}
}
- var w interface{}
+ var w any
dec := json.NewDecoder(strings.NewReader(s))
dec.UseNumber()
if err := dec.Decode(&w); err != nil {
- return err
+ return &func0WrapError{"fromjson", v, err}
}
if _, err := dec.Token(); err != io.EOF {
- return &funcTypeError{"fromjson", v}
+ return &func0TypeError{"fromjson", v}
}
return normalizeNumbers(w)
}
-func funcFormat(v, x interface{}) interface{} {
+func funcFormat(v, x any) any {
s, ok := x.(string)
if !ok {
- return &funcTypeError{"format", x}
+ return &func0TypeError{"format", x}
}
- fmt := "@" + s
- f := formatToFunc(fmt)
+ format := "@" + s
+ f := formatToFunc(format)
if f == nil {
- return &formatNotFoundError{fmt}
+ return &formatNotFoundError{format}
}
return internalFuncs[f.Name].callback(v, nil)
}
@@ -818,7 +820,7 @@ var htmlEscaper = strings.NewReplacer(
`"`, """,
)
-func funcToHTML(v interface{}) interface{} {
+func funcToHTML(v any) any {
switch x := funcToString(v).(type) {
case string:
return htmlEscaper.Replace(x)
@@ -827,7 +829,7 @@ func funcToHTML(v interface{}) interface{} {
}
}
-func funcToURI(v interface{}) interface{} {
+func funcToURI(v any) any {
switch x := funcToString(v).(type) {
case string:
return url.QueryEscape(x)
@@ -836,12 +838,25 @@ func funcToURI(v interface{}) interface{} {
}
}
+func funcToURId(v any) any {
+ switch x := funcToString(v).(type) {
+ case string:
+ x, err := url.QueryUnescape(x)
+ if err != nil {
+ return &func0WrapError{"@urid", v, err}
+ }
+ return x
+ default:
+ return x
+ }
+}
+
var csvEscaper = strings.NewReplacer(
`"`, `""`,
"\x00", `\0`,
)
-func funcToCSV(v interface{}) interface{} {
+func funcToCSV(v any) any {
return formatJoin("csv", v, ",", func(s string) string {
return `"` + csvEscaper.Replace(s) + `"`
})
@@ -855,7 +870,7 @@ var tsvEscaper = strings.NewReplacer(
"\x00", `\0`,
)
-func funcToTSV(v interface{}) interface{} {
+func funcToTSV(v any) any {
return formatJoin("tsv", v, "\t", tsvEscaper.Replace)
}
@@ -864,24 +879,24 @@ var shEscaper = strings.NewReplacer(
"\x00", `\0`,
)
-func funcToSh(v interface{}) interface{} {
- if _, ok := v.([]interface{}); !ok {
- v = []interface{}{v}
+func funcToSh(v any) any {
+ if _, ok := v.([]any); !ok {
+ v = []any{v}
}
return formatJoin("sh", v, " ", func(s string) string {
return "'" + shEscaper.Replace(s) + "'"
})
}
-func formatJoin(typ string, v interface{}, sep string, escape func(string) string) interface{} {
- vs, ok := v.([]interface{})
+func formatJoin(typ string, v any, sep string, escape func(string) string) any {
+ vs, ok := v.([]any)
if !ok {
- return &funcTypeError{"@" + typ, v}
+ return &func0TypeError{"@" + typ, v}
}
ss := make([]string, len(vs))
for i, v := range vs {
switch v := v.(type) {
- case []interface{}, map[string]interface{}:
+ case []any, map[string]any:
return &formatRowError{typ, v}
case string:
ss[i] = escape(v)
@@ -894,7 +909,7 @@ func formatJoin(typ string, v interface{}, sep string, escape func(string) strin
return strings.Join(ss, sep)
}
-func funcToBase64(v interface{}) interface{} {
+func funcToBase64(v any) any {
switch x := funcToString(v).(type) {
case string:
return base64.StdEncoding.EncodeToString([]byte(x))
@@ -903,7 +918,7 @@ func funcToBase64(v interface{}) interface{} {
}
}
-func funcToBase64d(v interface{}) interface{} {
+func funcToBase64d(v any) any {
switch x := funcToString(v).(type) {
case string:
if i := strings.IndexRune(x, base64.StdPadding); i >= 0 {
@@ -911,7 +926,7 @@ func funcToBase64d(v interface{}) interface{} {
}
y, err := base64.RawStdEncoding.DecodeString(x)
if err != nil {
- return err
+ return &func0WrapError{"@base64d", v, err}
}
return string(y)
default:
@@ -919,13 +934,13 @@ func funcToBase64d(v interface{}) interface{} {
}
}
-func funcIndex2(_, v, x interface{}) interface{} {
+func funcIndex2(_, v, x any) any {
switch x := x.(type) {
case string:
switch v := v.(type) {
case nil:
return nil
- case map[string]interface{}:
+ case map[string]any:
return v[x]
default:
return &expectedObjectError{v}
@@ -935,23 +950,23 @@ func funcIndex2(_, v, x interface{}) interface{} {
switch v := v.(type) {
case nil:
return nil
- case []interface{}:
+ case []any:
return index(v, i)
case string:
return indexString(v, i)
default:
return &expectedArrayError{v}
}
- case []interface{}:
+ case []any:
switch v := v.(type) {
case nil:
return nil
- case []interface{}:
+ case []any:
return indices(v, x)
default:
return &expectedArrayError{v}
}
- case map[string]interface{}:
+ case map[string]any:
if v == nil {
return nil
}
@@ -966,7 +981,7 @@ func funcIndex2(_, v, x interface{}) interface{} {
return funcSlice(nil, v, end, start)
default:
switch v.(type) {
- case []interface{}:
+ case []any:
return &arrayIndexNotNumberError{x}
case string:
return &stringIndexNotNumberError{x}
@@ -976,7 +991,7 @@ func funcIndex2(_, v, x interface{}) interface{} {
}
}
-func index(vs []interface{}, i int) interface{} {
+func index(vs []any, i int) any {
i = clampIndex(i, -1, len(vs))
if 0 <= i && i < len(vs) {
return vs[i]
@@ -984,7 +999,7 @@ func index(vs []interface{}, i int) interface{} {
return nil
}
-func indexString(s string, i int) interface{} {
+func indexString(s string, i int) any {
l := len([]rune(s))
i = clampIndex(i, -1, l)
if 0 <= i && i < l {
@@ -997,11 +1012,11 @@ func indexString(s string, i int) interface{} {
return nil
}
-func funcSlice(_, v, e, s interface{}) (r interface{}) {
+func funcSlice(_, v, e, s any) (r any) {
switch v := v.(type) {
case nil:
return nil
- case []interface{}:
+ case []any:
return slice(v, e, s)
case string:
return sliceString(v, e, s)
@@ -1010,7 +1025,7 @@ func funcSlice(_, v, e, s interface{}) (r interface{}) {
}
}
-func slice(vs []interface{}, e, s interface{}) interface{} {
+func slice(vs []any, e, s any) any {
var start, end int
if s != nil {
if i, ok := toInt(s); ok {
@@ -1031,7 +1046,7 @@ func slice(vs []interface{}, e, s interface{}) interface{} {
return vs[start:end]
}
-func sliceString(v string, e, s interface{}) interface{} {
+func sliceString(v string, e, s any) any {
var start, end int
l := len([]rune(v))
if s != nil {
@@ -1086,10 +1101,10 @@ func clampIndex(i, min, max int) int {
}
}
-func funcFlatten(v interface{}, args []interface{}) interface{} {
+func funcFlatten(v any, args []any) any {
vs, ok := values(v)
if !ok {
- return &funcTypeError{"flatten", v}
+ return &func0TypeError{"flatten", v}
}
var depth float64
if len(args) == 0 {
@@ -1097,18 +1112,18 @@ func funcFlatten(v interface{}, args []interface{}) interface{} {
} else {
depth, ok = toFloat(args[0])
if !ok {
- return &funcTypeError{"flatten", args[0]}
+ return &func0TypeError{"flatten", args[0]}
}
if depth < 0 {
return &flattenDepthError{depth}
}
}
- return flatten(nil, vs, depth)
+ return flatten([]any{}, vs, depth)
}
-func flatten(xs, vs []interface{}, depth float64) []interface{} {
+func flatten(xs, vs []any, depth float64) []any {
for _, v := range vs {
- if vs, ok := v.([]interface{}); ok && depth != 0 {
+ if vs, ok := v.([]any); ok && depth != 0 {
xs = flatten(xs, vs, depth-1)
} else {
xs = append(xs, v)
@@ -1118,10 +1133,10 @@ func flatten(xs, vs []interface{}, depth float64) []interface{} {
}
type rangeIter struct {
- value, end, step interface{}
+ value, end, step any
}
-func (iter *rangeIter) Next() (interface{}, bool) {
+func (iter *rangeIter) Next() (any, bool) {
if compare(iter.step, 0)*compare(iter.value, iter.end) >= 0 {
return nil, false
}
@@ -1130,64 +1145,64 @@ func (iter *rangeIter) Next() (interface{}, bool) {
return v, true
}
-func funcRange(_ interface{}, xs []interface{}) interface{} {
+func funcRange(_ any, xs []any) any {
for _, x := range xs {
switch x.(type) {
case int, float64, *big.Int:
default:
- return &funcTypeError{"range", x}
+ return &func0TypeError{"range", x}
}
}
return &rangeIter{xs[0], xs[1], xs[2]}
}
-func funcMin(v interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcMin(v any) any {
+ vs, ok := v.([]any)
if !ok {
- return &funcTypeError{"min", v}
+ return &func0TypeError{"min", v}
}
return minMaxBy(vs, vs, true)
}
-func funcMinBy(v, x interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcMinBy(v, x any) any {
+ vs, ok := v.([]any)
if !ok {
- return &funcTypeError{"min_by", v}
+ return &func1TypeError{"min_by", v, x}
}
- xs, ok := x.([]interface{})
+ xs, ok := x.([]any)
if !ok {
- return &funcTypeError{"min_by", x}
+ return &func1TypeError{"min_by", v, x}
}
if len(vs) != len(xs) {
- return &lengthMismatchError{"min_by", vs, xs}
+ return &func1WrapError{"min_by", v, x, &lengthMismatchError{}}
}
return minMaxBy(vs, xs, true)
}
-func funcMax(v interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcMax(v any) any {
+ vs, ok := v.([]any)
if !ok {
- return &funcTypeError{"max", v}
+ return &func0TypeError{"max", v}
}
return minMaxBy(vs, vs, false)
}
-func funcMaxBy(v, x interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcMaxBy(v, x any) any {
+ vs, ok := v.([]any)
if !ok {
- return &funcTypeError{"max_by", v}
+ return &func1TypeError{"max_by", v, x}
}
- xs, ok := x.([]interface{})
+ xs, ok := x.([]any)
if !ok {
- return &funcTypeError{"max_by", x}
+ return &func1TypeError{"max_by", v, x}
}
if len(vs) != len(xs) {
- return &lengthMismatchError{"max_by", vs, xs}
+ return &func1WrapError{"max_by", v, x, &lengthMismatchError{}}
}
return minMaxBy(vs, xs, false)
}
-func minMaxBy(vs, xs []interface{}, isMin bool) interface{} {
+func minMaxBy(vs, xs []any, isMin bool) any {
if len(vs) == 0 {
return nil
}
@@ -1201,20 +1216,23 @@ func minMaxBy(vs, xs []interface{}, isMin bool) interface{} {
}
type sortItem struct {
- value, key interface{}
+ value, key any
}
-func sortItems(name string, v, x interface{}) ([]*sortItem, error) {
- vs, ok := v.([]interface{})
+func sortItems(name string, v, x any) ([]*sortItem, error) {
+ vs, ok := v.([]any)
if !ok {
- return nil, &funcTypeError{name, v}
+ if strings.HasSuffix(name, "_by") {
+ return nil, &func1TypeError{name, v, x}
+ }
+ return nil, &func0TypeError{name, v}
}
- xs, ok := x.([]interface{})
+ xs, ok := x.([]any)
if !ok {
- return nil, &funcTypeError{name, x}
+ return nil, &func1TypeError{name, v, x}
}
if len(vs) != len(xs) {
- return nil, &lengthMismatchError{name, vs, xs}
+ return nil, &func1WrapError{name, v, x, &lengthMismatchError{}}
}
items := make([]*sortItem, len(vs))
for i, v := range vs {
@@ -1226,58 +1244,58 @@ func sortItems(name string, v, x interface{}) ([]*sortItem, error) {
return items, nil
}
-func funcSort(v interface{}) interface{} {
+func funcSort(v any) any {
return sortBy("sort", v, v)
}
-func funcSortBy(v, x interface{}) interface{} {
+func funcSortBy(v, x any) any {
return sortBy("sort_by", v, x)
}
-func sortBy(name string, v, x interface{}) interface{} {
+func sortBy(name string, v, x any) any {
items, err := sortItems(name, v, x)
if err != nil {
return err
}
- rs := make([]interface{}, len(items))
+ rs := make([]any, len(items))
for i, x := range items {
rs[i] = x.value
}
return rs
}
-func funcGroupBy(v, x interface{}) interface{} {
+func funcGroupBy(v, x any) any {
items, err := sortItems("group_by", v, x)
if err != nil {
return err
}
- var rs []interface{}
- var last interface{}
+ rs := []any{}
+ var last any
for i, r := range items {
if i == 0 || compare(last, r.key) != 0 {
- rs, last = append(rs, []interface{}{r.value}), r.key
+ rs, last = append(rs, []any{r.value}), r.key
} else {
- rs[len(rs)-1] = append(rs[len(rs)-1].([]interface{}), r.value)
+ rs[len(rs)-1] = append(rs[len(rs)-1].([]any), r.value)
}
}
return rs
}
-func funcUnique(v interface{}) interface{} {
+func funcUnique(v any) any {
return uniqueBy("unique", v, v)
}
-func funcUniqueBy(v, x interface{}) interface{} {
+func funcUniqueBy(v, x any) any {
return uniqueBy("unique_by", v, x)
}
-func uniqueBy(name string, v, x interface{}) interface{} {
+func uniqueBy(name string, v, x any) any {
items, err := sortItems(name, v, x)
if err != nil {
return err
}
- var rs []interface{}
- var last interface{}
+ rs := []any{}
+ var last any
for i, r := range items {
if i == 0 || compare(last, r.key) != 0 {
rs, last = append(rs, r.value), r.key
@@ -1286,17 +1304,17 @@ func uniqueBy(name string, v, x interface{}) interface{} {
return rs
}
-func funcJoin(v, x interface{}) interface{} {
+func funcJoin(v, x any) any {
vs, ok := values(v)
if !ok {
- return &funcTypeError{"join", v}
+ return &func1TypeError{"join", v, x}
}
if len(vs) == 0 {
return ""
}
sep, ok := x.(string)
if len(vs) > 1 && !ok {
- return &funcTypeError{"join", x}
+ return &func1TypeError{"join", v, x}
}
ss := make([]string, len(vs))
for i, v := range vs {
@@ -1330,22 +1348,22 @@ func funcExp10(v float64) float64 {
return math.Pow(10, v)
}
-func funcFrexp(v interface{}) interface{} {
+func funcFrexp(v any) any {
x, ok := toFloat(v)
if !ok {
- return &funcTypeError{"frexp", v}
+ return &func0TypeError{"frexp", v}
}
f, e := math.Frexp(x)
- return []interface{}{f, e}
+ return []any{f, e}
}
-func funcModf(v interface{}) interface{} {
+func funcModf(v any) any {
x, ok := toFloat(v)
if !ok {
- return &funcTypeError{"modf", v}
+ return &func0TypeError{"modf", v}
}
i, f := math.Modf(x)
- return []interface{}{f, i}
+ return []any{f, i}
}
func funcLgamma(v float64) float64 {
@@ -1381,36 +1399,36 @@ func funcYn(l, r float64) float64 {
return math.Yn(int(l), r)
}
-func funcInfinite(interface{}) interface{} {
+func funcInfinite(any) any {
return math.Inf(1)
}
-func funcIsfinite(v interface{}) interface{} {
+func funcIsfinite(v any) any {
x, ok := toFloat(v)
return ok && !math.IsInf(x, 0)
}
-func funcIsinfinite(v interface{}) interface{} {
+func funcIsinfinite(v any) any {
x, ok := toFloat(v)
return ok && math.IsInf(x, 0)
}
-func funcNan(interface{}) interface{} {
+func funcNan(any) any {
return math.NaN()
}
-func funcIsnan(v interface{}) interface{} {
+func funcIsnan(v any) any {
x, ok := toFloat(v)
if !ok {
if v == nil {
return false
}
- return &funcTypeError{"isnan", v}
+ return &func0TypeError{"isnan", v}
}
return math.IsNaN(x)
}
-func funcIsnormal(v interface{}) interface{} {
+func funcIsnormal(v any) any {
if v, ok := toFloat(v); ok {
e := math.Float64bits(v) & 0x7ff0000000000000 >> 52
return 0 < e && e < 0x7ff
@@ -1424,72 +1442,69 @@ func funcIsnormal(v interface{}) interface{} {
// functions.
type allocator map[uintptr]struct{}
-func funcAllocator(interface{}, []interface{}) interface{} {
+func funcAllocator(any, []any) any {
return allocator{}
}
-func (a allocator) allocated(v interface{}) bool {
+func (a allocator) allocated(v any) bool {
_, ok := a[reflect.ValueOf(v).Pointer()]
return ok
}
-func (a allocator) makeObject(l int) map[string]interface{} {
- v := make(map[string]interface{}, l)
+func (a allocator) makeObject(l int) map[string]any {
+ v := make(map[string]any, l)
if a != nil {
a[reflect.ValueOf(v).Pointer()] = struct{}{}
}
return v
}
-func (a allocator) makeArray(l, c int) []interface{} {
+func (a allocator) makeArray(l, c int) []any {
if c < l {
c = l
}
- v := make([]interface{}, l, c)
+ v := make([]any, l, c)
if a != nil {
a[reflect.ValueOf(v).Pointer()] = struct{}{}
}
return v
}
-func funcSetpath(v, p, n interface{}) interface{} {
+func funcSetpath(v, p, n any) any {
// There is no need to use an allocator on a single update.
return setpath(v, p, n, nil)
}
// Used in compiler#compileAssign and compiler#compileModify.
-func funcSetpathWithAllocator(v interface{}, args []interface{}) interface{} {
+func funcSetpathWithAllocator(v any, args []any) any {
return setpath(v, args[0], args[1], args[2].(allocator))
}
-func setpath(v, p, n interface{}, a allocator) interface{} {
- path, ok := p.([]interface{})
+func setpath(v, p, n any, a allocator) any {
+ path, ok := p.([]any)
if !ok {
- return &funcTypeError{"setpath", p}
+ return &func1TypeError{"setpath", v, p}
}
- var err error
- if v, err = update(v, path, n, a); err != nil {
- if err, ok := err.(*funcTypeError); ok {
- err.name = "setpath"
- }
- return err
+ u, err := update(v, path, n, a)
+ if err != nil {
+ return &func2WrapError{"setpath", v, p, n, err}
}
- return v
+ return u
}
-func funcDelpaths(v, p interface{}) interface{} {
+func funcDelpaths(v, p any) any {
return delpaths(v, p, allocator{})
}
// Used in compiler#compileAssign and compiler#compileModify.
-func funcDelpathsWithAllocator(v interface{}, args []interface{}) interface{} {
+func funcDelpathsWithAllocator(v any, args []any) any {
return delpaths(v, args[0], args[1].(allocator))
}
-func delpaths(v, p interface{}, a allocator) interface{} {
- paths, ok := p.([]interface{})
+func delpaths(v, p any, a allocator) any {
+ paths, ok := p.([]any)
if !ok {
- return &funcTypeError{"delpaths", p}
+ return &func1TypeError{"delpaths", v, p}
}
if len(paths) == 0 {
return v
@@ -1499,19 +1514,21 @@ func delpaths(v, p interface{}, a allocator) interface{} {
// jq -n "[0, 1, 2, 3] | delpaths([[1], [2]])" #=> [0, 3].
var empty struct{}
var err error
- for _, p := range paths {
- path, ok := p.([]interface{})
+ u := v
+ for _, q := range paths {
+ path, ok := q.([]any)
if !ok {
- return &funcTypeError{"delpaths", p}
+ return &func1WrapError{"delpaths", v, p, &expectedArrayError{q}}
}
- if v, err = update(v, path, empty, a); err != nil {
- return err
+ u, err = update(u, path, empty, a)
+ if err != nil {
+ return &func1WrapError{"delpaths", v, p, err}
}
}
- return deleteEmpty(v)
+ return deleteEmpty(u)
}
-func update(v interface{}, path []interface{}, n interface{}, a allocator) (interface{}, error) {
+func update(v any, path []any, n any, a allocator) (any, error) {
if len(path) == 0 {
return n, nil
}
@@ -1520,7 +1537,7 @@ func update(v interface{}, path []interface{}, n interface{}, a allocator) (inte
switch v := v.(type) {
case nil:
return updateObject(nil, p, path[1:], n, a)
- case map[string]interface{}:
+ case map[string]any:
return updateObject(v, p, path[1:], n, a)
case struct{}:
return v, nil
@@ -1532,18 +1549,18 @@ func update(v interface{}, path []interface{}, n interface{}, a allocator) (inte
switch v := v.(type) {
case nil:
return updateArrayIndex(nil, i, path[1:], n, a)
- case []interface{}:
+ case []any:
return updateArrayIndex(v, i, path[1:], n, a)
case struct{}:
return v, nil
default:
return nil, &expectedArrayError{v}
}
- case map[string]interface{}:
+ case map[string]any:
switch v := v.(type) {
case nil:
return updateArraySlice(nil, p, path[1:], n, a)
- case []interface{}:
+ case []any:
return updateArraySlice(v, p, path[1:], n, a)
case struct{}:
return v, nil
@@ -1552,7 +1569,7 @@ func update(v interface{}, path []interface{}, n interface{}, a allocator) (inte
}
default:
switch v.(type) {
- case []interface{}:
+ case []any:
return nil, &arrayIndexNotNumberError{p}
default:
return nil, &objectKeyNotStringError{p}
@@ -1560,7 +1577,7 @@ func update(v interface{}, path []interface{}, n interface{}, a allocator) (inte
}
}
-func updateObject(v map[string]interface{}, k string, path []interface{}, n interface{}, a allocator) (interface{}, error) {
+func updateObject(v map[string]any, k string, path []any, n any, a allocator) (any, error) {
x, ok := v[k]
if !ok && n == struct{}{} {
return v, nil
@@ -1581,13 +1598,13 @@ func updateObject(v map[string]interface{}, k string, path []interface{}, n inte
return w, nil
}
-func updateArrayIndex(v []interface{}, i int, path []interface{}, n interface{}, a allocator) (interface{}, error) {
- var x interface{}
+func updateArrayIndex(v []any, i int, path []any, n any, a allocator) (any, error) {
+ var x any
if j := clampIndex(i, -1, len(v)); j < 0 {
if n == struct{}{} {
return v, nil
}
- return nil, &funcTypeError{v: i}
+ return nil, &arrayIndexNegativeError{i}
} else if j < len(v) {
i = j
x = v[i]
@@ -1623,7 +1640,7 @@ func updateArrayIndex(v []interface{}, i int, path []interface{}, n interface{},
return w, nil
}
-func updateArraySlice(v []interface{}, m map[string]interface{}, path []interface{}, n interface{}, a allocator) (interface{}, error) {
+func updateArraySlice(v []any, m map[string]any, path []any, n any, a allocator) (any, error) {
s, ok := m["start"]
if !ok {
return nil, &expectedStartEndError{m}
@@ -1649,8 +1666,8 @@ func updateArraySlice(v []interface{}, m map[string]interface{}, path []interfac
return nil, err
}
switch u := u.(type) {
- case []interface{}:
- var w []interface{}
+ case []any:
+ var w []any
if len(u) == end-start && a.allocated(v) {
w = v
} else {
@@ -1661,7 +1678,7 @@ func updateArraySlice(v []interface{}, m map[string]interface{}, path []interfac
copy(w[start:], u)
return w, nil
case struct{}:
- var w []interface{}
+ var w []any
if a.allocated(v) {
w = v
} else {
@@ -1677,11 +1694,11 @@ func updateArraySlice(v []interface{}, m map[string]interface{}, path []interfac
}
}
-func deleteEmpty(v interface{}) interface{} {
+func deleteEmpty(v any) any {
switch v := v.(type) {
case struct{}:
return nil
- case map[string]interface{}:
+ case map[string]any:
for k, w := range v {
if w == struct{}{} {
delete(v, k)
@@ -1690,7 +1707,7 @@ func deleteEmpty(v interface{}) interface{} {
}
}
return v
- case []interface{}:
+ case []any:
var j int
for _, w := range v {
if w != struct{}{} {
@@ -1707,63 +1724,63 @@ func deleteEmpty(v interface{}) interface{} {
}
}
-func funcGetpath(v, p interface{}) interface{} {
- keys, ok := p.([]interface{})
+func funcGetpath(v, p any) any {
+ path, ok := p.([]any)
if !ok {
- return &funcTypeError{"getpath", p}
+ return &func1TypeError{"getpath", v, p}
}
u := v
- for _, x := range keys {
+ for _, x := range path {
switch v.(type) {
- case nil, []interface{}, map[string]interface{}:
+ case nil, []any, map[string]any:
v = funcIndex2(nil, v, x)
- if _, ok := v.(error); ok {
- return &getpathError{u, p}
+ if err, ok := v.(error); ok {
+ return &func1WrapError{"getpath", u, p, err}
}
default:
- return &getpathError{u, p}
+ return &func1TypeError{"getpath", u, p}
}
}
return v
}
-func funcTranspose(v interface{}) interface{} {
- vss, ok := v.([]interface{})
+func funcTranspose(v any) any {
+ vss, ok := v.([]any)
if !ok {
- return &funcTypeError{"transpose", v}
+ return &func0TypeError{"transpose", v}
}
if len(vss) == 0 {
- return []interface{}{}
+ return []any{}
}
var l int
for _, vs := range vss {
- vs, ok := vs.([]interface{})
+ vs, ok := vs.([]any)
if !ok {
- return &funcTypeError{"transpose", v}
+ return &func0TypeError{"transpose", v}
}
if k := len(vs); l < k {
l = k
}
}
- wss := make([][]interface{}, l)
- xs := make([]interface{}, l)
+ wss := make([][]any, l)
+ xs := make([]any, l)
for i, k := 0, len(vss); i < l; i++ {
- s := make([]interface{}, k)
+ s := make([]any, k)
wss[i] = s
xs[i] = s
}
for i, vs := range vss {
- for j, v := range vs.([]interface{}) {
+ for j, v := range vs.([]any) {
wss[j][i] = v
}
}
return xs
}
-func funcBsearch(v, t interface{}) interface{} {
- vs, ok := v.([]interface{})
+func funcBsearch(v, t any) any {
+ vs, ok := v.([]any)
if !ok {
- return &funcTypeError{"bsearch", v}
+ return &func1TypeError{"bsearch", v, t}
}
i := sort.Search(len(vs), func(i int) bool {
return compare(vs[i], t) >= 0
@@ -1774,23 +1791,23 @@ func funcBsearch(v, t interface{}) interface{} {
return -i - 1
}
-func funcGmtime(v interface{}) interface{} {
+func funcGmtime(v any) any {
if v, ok := toFloat(v); ok {
return epochToArray(v, time.UTC)
}
- return &funcTypeError{"gmtime", v}
+ return &func0TypeError{"gmtime", v}
}
-func funcLocaltime(v interface{}) interface{} {
+func funcLocaltime(v any) any {
if v, ok := toFloat(v); ok {
return epochToArray(v, time.Local)
}
- return &funcTypeError{"localtime", v}
+ return &func0TypeError{"localtime", v}
}
-func epochToArray(v float64, loc *time.Location) []interface{} {
+func epochToArray(v float64, loc *time.Location) []any {
t := time.Unix(int64(v), int64((v-math.Floor(v))*1e9)).In(loc)
- return []interface{}{
+ return []any{
t.Year(),
int(t.Month()) - 1,
t.Day(),
@@ -1802,133 +1819,143 @@ func epochToArray(v float64, loc *time.Location) []interface{} {
}
}
-func funcMktime(v interface{}) interface{} {
- if a, ok := v.([]interface{}); ok {
- t, err := arrayToTime("mktime", a, time.UTC)
- if err != nil {
- return err
- }
- return timeToEpoch(t)
+func funcMktime(v any) any {
+ a, ok := v.([]any)
+ if !ok {
+ return &func0TypeError{"mktime", v}
}
- return &funcTypeError{"mktime", v}
+ t, err := arrayToTime(a, time.UTC)
+ if err != nil {
+ return &func0WrapError{"mktime", v, err}
+ }
+ return timeToEpoch(t)
}
func timeToEpoch(t time.Time) float64 {
return float64(t.Unix()) + float64(t.Nanosecond())/1e9
}
-func funcStrftime(v, x interface{}) interface{} {
+func funcStrftime(v, x any) any {
if w, ok := toFloat(v); ok {
v = epochToArray(w, time.UTC)
}
- if a, ok := v.([]interface{}); ok {
- if format, ok := x.(string); ok {
- t, err := arrayToTime("strftime", a, time.UTC)
- if err != nil {
- return err
- }
- return timefmt.Format(t, format)
- }
- return &funcTypeError{"strftime", x}
+ a, ok := v.([]any)
+ if !ok {
+ return &func1TypeError{"strftime", v, x}
+ }
+ format, ok := x.(string)
+ if !ok {
+ return &func1TypeError{"strftime", v, x}
+ }
+ t, err := arrayToTime(a, time.UTC)
+ if err != nil {
+ return &func1WrapError{"strftime", v, x, err}
}
- return &funcTypeError{"strftime", v}
+ return timefmt.Format(t, format)
}
-func funcStrflocaltime(v, x interface{}) interface{} {
+func funcStrflocaltime(v, x any) any {
if w, ok := toFloat(v); ok {
v = epochToArray(w, time.Local)
}
- if a, ok := v.([]interface{}); ok {
- if format, ok := x.(string); ok {
- t, err := arrayToTime("strflocaltime", a, time.Local)
- if err != nil {
- return err
- }
- return timefmt.Format(t, format)
- }
- return &funcTypeError{"strflocaltime", x}
+ a, ok := v.([]any)
+ if !ok {
+ return &func1TypeError{"strflocaltime", v, x}
}
- return &funcTypeError{"strflocaltime", v}
+ format, ok := x.(string)
+ if !ok {
+ return &func1TypeError{"strflocaltime", v, x}
+ }
+ t, err := arrayToTime(a, time.Local)
+ if err != nil {
+ return &func1WrapError{"strflocaltime", v, x, err}
+ }
+ return timefmt.Format(t, format)
}
-func funcStrptime(v, x interface{}) interface{} {
- if v, ok := v.(string); ok {
- if format, ok := x.(string); ok {
- t, err := timefmt.Parse(v, format)
- if err != nil {
- return err
- }
- var s time.Time
- if t == s {
- return &funcTypeError{"strptime", v}
- }
- return epochToArray(timeToEpoch(t), time.UTC)
- }
- return &funcTypeError{"strptime", x}
+func funcStrptime(v, x any) any {
+ s, ok := v.(string)
+ if !ok {
+ return &func1TypeError{"strptime", v, x}
+ }
+ format, ok := x.(string)
+ if !ok {
+ return &func1TypeError{"strptime", v, x}
+ }
+ t, err := timefmt.Parse(s, format)
+ if err != nil {
+ return &func1WrapError{"strptime", v, x, err}
+ }
+ var u time.Time
+ if t == u {
+ return &func1TypeError{"strptime", v, x}
}
- return &funcTypeError{"strptime", v}
+ return epochToArray(timeToEpoch(t), time.UTC)
}
-func arrayToTime(name string, a []interface{}, loc *time.Location) (time.Time, error) {
+func arrayToTime(a []any, loc *time.Location) (time.Time, error) {
var t time.Time
if len(a) != 8 {
- return t, &funcTypeError{name, a}
+ return t, &timeArrayError{}
}
var y, m, d, h, min, sec, nsec int
- if x, ok := toInt(a[0]); ok {
- y = x
- } else {
- return t, &funcTypeError{name, a}
+ var ok bool
+ if y, ok = toInt(a[0]); !ok {
+ return t, &timeArrayError{}
}
- if x, ok := toInt(a[1]); ok {
- m = x + 1
+ if m, ok = toInt(a[1]); ok {
+ m++
} else {
- return t, &funcTypeError{name, a}
+ return t, &timeArrayError{}
}
- if x, ok := toInt(a[2]); ok {
- d = x
- } else {
- return t, &funcTypeError{name, a}
+ if d, ok = toInt(a[2]); !ok {
+ return t, &timeArrayError{}
}
- if x, ok := toInt(a[3]); ok {
- h = x
- } else {
- return t, &funcTypeError{name, a}
+ if h, ok = toInt(a[3]); !ok {
+ return t, &timeArrayError{}
}
- if x, ok := toInt(a[4]); ok {
- min = x
- } else {
- return t, &funcTypeError{name, a}
+ if min, ok = toInt(a[4]); !ok {
+ return t, &timeArrayError{}
}
if x, ok := toFloat(a[5]); ok {
sec = int(x)
nsec = int((x - math.Floor(x)) * 1e9)
} else {
- return t, &funcTypeError{name, a}
+ return t, &timeArrayError{}
+ }
+ if _, ok = toFloat(a[6]); !ok {
+ return t, &timeArrayError{}
+ }
+ if _, ok = toFloat(a[7]); !ok {
+ return t, &timeArrayError{}
}
return time.Date(y, time.Month(m), d, h, min, sec, nsec, loc), nil
}
-func funcNow(interface{}) interface{} {
+func funcNow(any) any {
return timeToEpoch(time.Now())
}
-func funcMatch(v, re, fs, testing interface{}) interface{} {
+func funcMatch(v, re, fs, testing any) any {
+ name := "match"
+ if testing == true {
+ name = "test"
+ }
var flags string
if fs != nil {
v, ok := fs.(string)
if !ok {
- return &funcTypeError{"match", fs}
+ return &func2TypeError{name, v, re, fs}
}
flags = v
}
s, ok := v.(string)
if !ok {
- return &funcTypeError{"match", v}
+ return &func2TypeError{name, v, re, fs}
}
restr, ok := re.(string)
if !ok {
- return &funcTypeError{"match", v}
+ return &func2TypeError{name, v, re, fs}
}
r, err := compileRegexp(restr, flags)
if err != nil {
@@ -1946,16 +1973,16 @@ func funcMatch(v, re, fs, testing interface{}) interface{} {
xs = [][]int{got}
}
}
- res, names := make([]interface{}, len(xs)), r.SubexpNames()
+ res, names := make([]any, len(xs)), r.SubexpNames()
for i, x := range xs {
- captures := make([]interface{}, (len(x)-2)/2)
+ captures := make([]any, (len(x)-2)/2)
for j := 1; j < len(x)/2; j++ {
- var name interface{}
+ var name any
if n := names[j]; n != "" {
name = n
}
if x[j*2] < 0 {
- captures[j-1] = map[string]interface{}{
+ captures[j-1] = map[string]any{
"name": name,
"offset": -1,
"length": 0,
@@ -1963,14 +1990,14 @@ func funcMatch(v, re, fs, testing interface{}) interface{} {
}
continue
}
- captures[j-1] = map[string]interface{}{
+ captures[j-1] = map[string]any{
"name": name,
"offset": len([]rune(s[:x[j*2]])),
"length": len([]rune(s[:x[j*2+1]])) - len([]rune(s[:x[j*2]])),
"string": s[x[j*2]:x[j*2+1]],
}
}
- res[i] = map[string]interface{}{
+ res[i] = map[string]any{
"offset": len([]rune(s[:x[0]])),
"length": len([]rune(s[:x[1]])) - len([]rune(s[:x[0]])),
"string": s[x[0]:x[1]],
@@ -2000,19 +2027,19 @@ func compileRegexp(re, flags string) (*regexp.Regexp, error) {
return r, nil
}
-func funcCapture(v interface{}) interface{} {
- vs, ok := v.(map[string]interface{})
+func funcCapture(v any) any {
+ vs, ok := v.(map[string]any)
if !ok {
return &expectedObjectError{v}
}
v = vs["captures"]
- captures, ok := v.([]interface{})
+ captures, ok := v.([]any)
if !ok {
return &expectedArrayError{v}
}
- w := make(map[string]interface{}, len(captures))
+ w := make(map[string]any, len(captures))
for _, capture := range captures {
- if capture, ok := capture.(map[string]interface{}); ok {
+ if capture, ok := capture.(map[string]any); ok {
if name, ok := capture["name"].(string); ok {
w[name] = capture["string"]
}
@@ -2021,7 +2048,7 @@ func funcCapture(v interface{}) interface{} {
return w
}
-func funcError(v interface{}, args []interface{}) interface{} {
+func funcError(v any, args []any) any {
if len(args) > 0 {
v = args[0]
}
@@ -2032,22 +2059,22 @@ func funcError(v interface{}, args []interface{}) interface{} {
return &exitCodeError{v, code, false}
}
-func funcHalt(interface{}) interface{} {
+func funcHalt(any) any {
return &exitCodeError{nil, 0, true}
}
-func funcHaltError(v interface{}, args []interface{}) interface{} {
+func funcHaltError(v any, args []any) any {
code := 5
if len(args) > 0 {
var ok bool
if code, ok = toInt(args[0]); !ok {
- return &funcTypeError{"halt_error", args[0]}
+ return &func0TypeError{"halt_error", args[0]}
}
}
return &exitCodeError{v, code, true}
}
-func toInt(x interface{}) (int, bool) {
+func toInt(x any) (int, bool) {
switch x := x.(type) {
case int:
return x, true
@@ -2078,7 +2105,7 @@ func floatToInt(x float64) int {
return math.MinInt
}
-func toFloat(x interface{}) (float64, bool) {
+func toFloat(x any) (float64, bool) {
switch x := x.(type) {
case int:
return float64(x), true
diff --git a/go.dev.mod b/go.dev.mod
index 26dfb59..9a0579c 100644
--- a/go.dev.mod
+++ b/go.dev.mod
@@ -1,6 +1,6 @@
module github.com/itchyny/gojq
-go 1.17
+go 1.18
require (
github.com/itchyny/astgen-go v0.0.0-20210914105503-cc8fccf6f972 // indirect
diff --git a/go.mod b/go.mod
index 7cfd97e..8b12ad4 100644
--- a/go.mod
+++ b/go.mod
@@ -1,16 +1,16 @@
module github.com/itchyny/gojq
-go 1.17
+go 1.18
require (
github.com/google/go-cmp v0.5.4
github.com/itchyny/timefmt-go v0.1.5
- github.com/mattn/go-isatty v0.0.16
+ github.com/mattn/go-isatty v0.0.19
github.com/mattn/go-runewidth v0.0.14
gopkg.in/yaml.v3 v3.0.1
)
require (
- github.com/rivo/uniseg v0.2.0 // indirect
- golang.org/x/sys v0.2.0 // indirect
+ github.com/rivo/uniseg v0.4.4 // indirect
+ golang.org/x/sys v0.8.0 // indirect
)
diff --git a/go.sum b/go.sum
index b5d4dd1..5b4e692 100644
--- a/go.sum
+++ b/go.sum
@@ -2,15 +2,16 @@ github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
-github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
-golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
+github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
diff --git a/iter.go b/iter.go
index 9ee5ad6..d0bed96 100644
--- a/iter.go
+++ b/iter.go
@@ -2,11 +2,11 @@ package gojq
// Iter is an interface for an iterator.
type Iter interface {
- Next() (interface{}, bool)
+ Next() (any, bool)
}
// NewIter creates a new [Iter] from values.
-func NewIter(values ...interface{}) Iter {
+func NewIter(values ...any) Iter {
switch len(values) {
case 0:
return emptyIter{}
@@ -20,16 +20,16 @@ func NewIter(values ...interface{}) Iter {
type emptyIter struct{}
-func (emptyIter) Next() (interface{}, bool) {
+func (emptyIter) Next() (any, bool) {
return nil, false
}
type unitIter struct {
- value interface{}
+ value any
done bool
}
-func (iter *unitIter) Next() (interface{}, bool) {
+func (iter *unitIter) Next() (any, bool) {
if iter.done {
return nil, false
}
@@ -37,9 +37,9 @@ func (iter *unitIter) Next() (interface{}, bool) {
return iter.value, true
}
-type sliceIter []interface{}
+type sliceIter []any
-func (iter *sliceIter) Next() (interface{}, bool) {
+func (iter *sliceIter) Next() (any, bool) {
if len(*iter) == 0 {
return nil, false
}
diff --git a/module_loader.go b/module_loader.go
index fff442d..599e37b 100644
--- a/module_loader.go
+++ b/module_loader.go
@@ -14,11 +14,11 @@ import (
// Implement following optional methods. Use [NewModuleLoader] to load local modules.
//
// LoadModule(string) (*Query, error)
-// LoadModuleWithMeta(string, map[string]interface{}) (*Query, error)
+// LoadModuleWithMeta(string, map[string]any) (*Query, error)
// LoadInitModules() ([]*Query, error)
-// LoadJSON(string) (interface{}, error)
-// LoadJSONWithMeta(string, map[string]interface{}) (interface{}, error)
-type ModuleLoader interface{}
+// LoadJSON(string) (any, error)
+// LoadJSONWithMeta(string, map[string]any) (any, error)
+type ModuleLoader any
// NewModuleLoader creates a new [ModuleLoader] reading local modules in the paths.
func NewModuleLoader(paths []string) ModuleLoader {
@@ -58,7 +58,7 @@ func (l *moduleLoader) LoadInitModules() ([]*Query, error) {
return qs, nil
}
-func (l *moduleLoader) LoadModuleWithMeta(name string, meta map[string]interface{}) (*Query, error) {
+func (l *moduleLoader) LoadModuleWithMeta(name string, meta map[string]any) (*Query, error) {
path, err := l.lookupModule(name, ".jq", meta)
if err != nil {
return nil, err
@@ -74,7 +74,7 @@ func (l *moduleLoader) LoadModuleWithMeta(name string, meta map[string]interface
return q, nil
}
-func (l *moduleLoader) LoadJSONWithMeta(name string, meta map[string]interface{}) (interface{}, error) {
+func (l *moduleLoader) LoadJSONWithMeta(name string, meta map[string]any) (any, error) {
path, err := l.lookupModule(name, ".json", meta)
if err != nil {
return nil, err
@@ -84,11 +84,11 @@ func (l *moduleLoader) LoadJSONWithMeta(name string, meta map[string]interface{}
return nil, err
}
defer f.Close()
- var vals []interface{}
+ vals := []any{}
dec := json.NewDecoder(f)
dec.UseNumber()
for {
- var val interface{}
+ var val any
if err := dec.Decode(&val); err != nil {
if err == io.EOF {
break
@@ -107,7 +107,7 @@ func (l *moduleLoader) LoadJSONWithMeta(name string, meta map[string]interface{}
return vals, nil
}
-func (l *moduleLoader) lookupModule(name, extension string, meta map[string]interface{}) (string, error) {
+func (l *moduleLoader) lookupModule(name, extension string, meta map[string]any) (string, error) {
paths := l.paths
if path := searchPath(meta); path != "" {
paths = append([]string{path}, paths...)
@@ -146,7 +146,7 @@ func parseModule(path, cnt string) (*Query, error) {
return q, nil
}
-func searchPath(meta map[string]interface{}) string {
+func searchPath(meta map[string]any) string {
x, ok := meta["search"]
if !ok {
return ""
diff --git a/normalize.go b/normalize.go
index bd0ddda..2bfcd21 100644
--- a/normalize.go
+++ b/normalize.go
@@ -7,7 +7,7 @@ import (
"strings"
)
-func normalizeNumber(v json.Number) interface{} {
+func normalizeNumber(v json.Number) any {
if i, err := v.Int64(); err == nil && math.MinInt <= i && i <= math.MaxInt {
return int(i)
}
@@ -25,7 +25,7 @@ func normalizeNumber(v json.Number) interface{} {
return math.Inf(1)
}
-func normalizeNumbers(v interface{}) interface{} {
+func normalizeNumbers(v any) any {
switch v := v.(type) {
case json.Number:
return normalizeNumber(v)
@@ -68,12 +68,12 @@ func normalizeNumbers(v interface{}) interface{} {
return int(v)
case float32:
return float64(v)
- case []interface{}:
+ case []any:
for i, x := range v {
v[i] = normalizeNumbers(x)
}
return v
- case map[string]interface{}:
+ case map[string]any:
for k, x := range v {
v[k] = normalizeNumbers(x)
}
diff --git a/operator.go b/operator.go
index 071b3d6..73a548e 100644
--- a/operator.go
+++ b/operator.go
@@ -208,14 +208,14 @@ func (op Operator) getFunc() string {
}
func binopTypeSwitch(
- l, r interface{},
- callbackInts func(_, _ int) interface{},
- callbackFloats func(_, _ float64) interface{},
- callbackBigInts func(_, _ *big.Int) interface{},
- callbackStrings func(_, _ string) interface{},
- callbackArrays func(_, _ []interface{}) interface{},
- callbackMaps func(_, _ map[string]interface{}) interface{},
- fallback func(_, _ interface{}) interface{}) interface{} {
+ l, r any,
+ callbackInts func(_, _ int) any,
+ callbackFloats func(_, _ float64) any,
+ callbackBigInts func(_, _ *big.Int) any,
+ callbackStrings func(_, _ string) any,
+ callbackArrays func(_, _ []any) any,
+ callbackMaps func(_, _ map[string]any) any,
+ fallback func(_, _ any) any) any {
switch l := l.(type) {
case int:
switch r := r.(type) {
@@ -257,16 +257,16 @@ func binopTypeSwitch(
default:
return fallback(l, r)
}
- case []interface{}:
+ case []any:
switch r := r.(type) {
- case []interface{}:
+ case []any:
return callbackArrays(l, r)
default:
return fallback(l, r)
}
- case map[string]interface{}:
+ case map[string]any:
switch r := r.(type) {
- case map[string]interface{}:
+ case map[string]any:
return callbackMaps(l, r)
default:
return fallback(l, r)
@@ -276,7 +276,7 @@ func binopTypeSwitch(
}
}
-func funcOpPlus(v interface{}) interface{} {
+func funcOpPlus(v any) any {
switch v := v.(type) {
case int:
return v
@@ -289,7 +289,7 @@ func funcOpPlus(v interface{}) interface{} {
}
}
-func funcOpNegate(v interface{}) interface{} {
+func funcOpNegate(v any) any {
switch v := v.(type) {
case int:
return -v
@@ -302,38 +302,38 @@ func funcOpNegate(v interface{}) interface{} {
}
}
-func funcOpAdd(_, l, r interface{}) interface{} {
+func funcOpAdd(_, l, r any) any {
return binopTypeSwitch(l, r,
- func(l, r int) interface{} {
+ func(l, r int) any {
if v := l + r; (v >= l) == (r >= 0) {
return v
}
x, y := big.NewInt(int64(l)), big.NewInt(int64(r))
return x.Add(x, y)
},
- func(l, r float64) interface{} { return l + r },
- func(l, r *big.Int) interface{} { return new(big.Int).Add(l, r) },
- func(l, r string) interface{} { return l + r },
- func(l, r []interface{}) interface{} {
+ func(l, r float64) any { return l + r },
+ func(l, r *big.Int) any { return new(big.Int).Add(l, r) },
+ func(l, r string) any { return l + r },
+ func(l, r []any) any {
if len(l) == 0 {
return r
}
if len(r) == 0 {
return l
}
- v := make([]interface{}, len(l)+len(r))
+ v := make([]any, len(l)+len(r))
copy(v, l)
copy(v[len(l):], r)
return v
},
- func(l, r map[string]interface{}) interface{} {
+ func(l, r map[string]any) any {
if len(l) == 0 {
return r
}
if len(r) == 0 {
return l
}
- m := make(map[string]interface{}, len(l)+len(r))
+ m := make(map[string]any, len(l)+len(r))
for k, v := range l {
m[k] = v
}
@@ -342,7 +342,7 @@ func funcOpAdd(_, l, r interface{}) interface{} {
}
return m
},
- func(l, r interface{}) interface{} {
+ func(l, r any) any {
if l == nil {
return r
}
@@ -354,20 +354,20 @@ func funcOpAdd(_, l, r interface{}) interface{} {
)
}
-func funcOpSub(_, l, r interface{}) interface{} {
+func funcOpSub(_, l, r any) any {
return binopTypeSwitch(l, r,
- func(l, r int) interface{} {
+ func(l, r int) any {
if v := l - r; (v <= l) == (r >= 0) {
return v
}
x, y := big.NewInt(int64(l)), big.NewInt(int64(r))
return x.Sub(x, y)
},
- func(l, r float64) interface{} { return l - r },
- func(l, r *big.Int) interface{} { return new(big.Int).Sub(l, r) },
- func(l, r string) interface{} { return &binopTypeError{"subtract", l, r} },
- func(l, r []interface{}) interface{} {
- v := make([]interface{}, 0, len(l))
+ func(l, r float64) any { return l - r },
+ func(l, r *big.Int) any { return new(big.Int).Sub(l, r) },
+ func(l, r string) any { return &binopTypeError{"subtract", l, r} },
+ func(l, r []any) any {
+ v := make([]any, 0, len(l))
L:
for _, l := range l {
for _, r := range r {
@@ -379,26 +379,26 @@ func funcOpSub(_, l, r interface{}) interface{} {
}
return v
},
- func(l, r map[string]interface{}) interface{} { return &binopTypeError{"subtract", l, r} },
- func(l, r interface{}) interface{} { return &binopTypeError{"subtract", l, r} },
+ func(l, r map[string]any) any { return &binopTypeError{"subtract", l, r} },
+ func(l, r any) any { return &binopTypeError{"subtract", l, r} },
)
}
-func funcOpMul(_, l, r interface{}) interface{} {
+func funcOpMul(_, l, r any) any {
return binopTypeSwitch(l, r,
- func(l, r int) interface{} {
+ func(l, r int) any {
if v := l * r; r == 0 || v/r == l {
return v
}
x, y := big.NewInt(int64(l)), big.NewInt(int64(r))
return x.Mul(x, y)
},
- func(l, r float64) interface{} { return l * r },
- func(l, r *big.Int) interface{} { return new(big.Int).Mul(l, r) },
- func(l, r string) interface{} { return &binopTypeError{"multiply", l, r} },
- func(l, r []interface{}) interface{} { return &binopTypeError{"multiply", l, r} },
+ func(l, r float64) any { return l * r },
+ func(l, r *big.Int) any { return new(big.Int).Mul(l, r) },
+ func(l, r string) any { return &binopTypeError{"multiply", l, r} },
+ func(l, r []any) any { return &binopTypeError{"multiply", l, r} },
deepMergeObjects,
- func(l, r interface{}) interface{} {
+ func(l, r any) any {
if l, ok := l.(string); ok {
if r, ok := toFloat(r); ok {
return repeatString(l, r)
@@ -414,15 +414,15 @@ func funcOpMul(_, l, r interface{}) interface{} {
)
}
-func deepMergeObjects(l, r map[string]interface{}) interface{} {
- m := make(map[string]interface{}, len(l)+len(r))
+func deepMergeObjects(l, r map[string]any) any {
+ m := make(map[string]any, len(l)+len(r))
for k, v := range l {
m[k] = v
}
for k, v := range r {
if mk, ok := m[k]; ok {
- if mk, ok := mk.(map[string]interface{}); ok {
- if w, ok := v.(map[string]interface{}); ok {
+ if mk, ok := mk.(map[string]any); ok {
+ if w, ok := v.(map[string]any); ok {
v = deepMergeObjects(mk, w)
}
}
@@ -432,19 +432,19 @@ func deepMergeObjects(l, r map[string]interface{}) interface{} {
return m
}
-func repeatString(s string, n float64) interface{} {
+func repeatString(s string, n float64) any {
if n <= 0.0 || len(s) > 0 && n > float64(0x10000000/len(s)) || math.IsNaN(n) {
return nil
}
- if n < 1.0 {
+ if int(n) < 1 {
return s
}
return strings.Repeat(s, int(n))
}
-func funcOpDiv(_, l, r interface{}) interface{} {
+func funcOpDiv(_, l, r any) any {
return binopTypeSwitch(l, r,
- func(l, r int) interface{} {
+ func(l, r int) any {
if r == 0 {
if l == 0 {
return math.NaN()
@@ -456,7 +456,7 @@ func funcOpDiv(_, l, r interface{}) interface{} {
}
return float64(l) / float64(r)
},
- func(l, r float64) interface{} {
+ func(l, r float64) any {
if r == 0.0 {
if l == 0.0 {
return math.NaN()
@@ -465,7 +465,7 @@ func funcOpDiv(_, l, r interface{}) interface{} {
}
return l / r
},
- func(l, r *big.Int) interface{} {
+ func(l, r *big.Int) any {
if r.Sign() == 0 {
if l.Sign() == 0 {
return math.NaN()
@@ -478,78 +478,78 @@ func funcOpDiv(_, l, r interface{}) interface{} {
}
return bigToFloat(l) / bigToFloat(r)
},
- func(l, r string) interface{} {
+ func(l, r string) any {
if l == "" {
- return []interface{}{}
+ return []any{}
}
xs := strings.Split(l, r)
- vs := make([]interface{}, len(xs))
+ vs := make([]any, len(xs))
for i, x := range xs {
vs[i] = x
}
return vs
},
- func(l, r []interface{}) interface{} { return &binopTypeError{"divide", l, r} },
- func(l, r map[string]interface{}) interface{} { return &binopTypeError{"divide", l, r} },
- func(l, r interface{}) interface{} { return &binopTypeError{"divide", l, r} },
+ func(l, r []any) any { return &binopTypeError{"divide", l, r} },
+ func(l, r map[string]any) any { return &binopTypeError{"divide", l, r} },
+ func(l, r any) any { return &binopTypeError{"divide", l, r} },
)
}
-func funcOpMod(_, l, r interface{}) interface{} {
+func funcOpMod(_, l, r any) any {
return binopTypeSwitch(l, r,
- func(l, r int) interface{} {
+ func(l, r int) any {
if r == 0 {
return &zeroModuloError{l, r}
}
return l % r
},
- func(l, r float64) interface{} {
+ func(l, r float64) any {
ri := floatToInt(r)
if ri == 0 {
return &zeroModuloError{l, r}
}
return floatToInt(l) % ri
},
- func(l, r *big.Int) interface{} {
+ func(l, r *big.Int) any {
if r.Sign() == 0 {
return &zeroModuloError{l, r}
}
return new(big.Int).Rem(l, r)
},
- func(l, r string) interface{} { return &binopTypeError{"modulo", l, r} },
- func(l, r []interface{}) interface{} { return &binopTypeError{"modulo", l, r} },
- func(l, r map[string]interface{}) interface{} { return &binopTypeError{"modulo", l, r} },
- func(l, r interface{}) interface{} { return &binopTypeError{"modulo", l, r} },
+ func(l, r string) any { return &binopTypeError{"modulo", l, r} },
+ func(l, r []any) any { return &binopTypeError{"modulo", l, r} },
+ func(l, r map[string]any) any { return &binopTypeError{"modulo", l, r} },
+ func(l, r any) any { return &binopTypeError{"modulo", l, r} },
)
}
-func funcOpAlt(_, l, r interface{}) interface{} {
+func funcOpAlt(_, l, r any) any {
if l == nil || l == false {
return r
}
return l
}
-func funcOpEq(_, l, r interface{}) interface{} {
+func funcOpEq(_, l, r any) any {
return compare(l, r) == 0
}
-func funcOpNe(_, l, r interface{}) interface{} {
+func funcOpNe(_, l, r any) any {
return compare(l, r) != 0
}
-func funcOpGt(_, l, r interface{}) interface{} {
+func funcOpGt(_, l, r any) any {
return compare(l, r) > 0
}
-func funcOpLt(_, l, r interface{}) interface{} {
+func funcOpLt(_, l, r any) any {
return compare(l, r) < 0
}
-func funcOpGe(_, l, r interface{}) interface{} {
+func funcOpGe(_, l, r any) any {
return compare(l, r) >= 0
}
-func funcOpLe(_, l, r interface{}) interface{} {
+func funcOpLe(_, l, r any) any {
return compare(l, r) <= 0
}
diff --git a/option.go b/option.go
index 6ccfa9b..f1a110f 100644
--- a/option.go
+++ b/option.go
@@ -39,8 +39,7 @@ func WithVariables(variables []string) CompilerOption {
// function. If you want to emit multiple values, call the empty function,
// accept a filter for its argument, or call another built-in function, then
// use LoadInitModules of the module loader.
-func WithFunction(name string, minarity, maxarity int,
- f func(interface{}, []interface{}) interface{}) CompilerOption {
+func WithFunction(name string, minarity, maxarity int, f func(any, []any) any) CompilerOption {
return withFunction(name, minarity, maxarity, false, f)
}
@@ -49,17 +48,15 @@ func WithFunction(name string, minarity, maxarity int,
// returns an Iter to emit multiple values. You cannot define both iterator and
// non-iterator functions of the same name (with possibly different arities).
// See also [NewIter], which can be used to convert values or an error to an Iter.
-func WithIterFunction(name string, minarity, maxarity int,
- f func(interface{}, []interface{}) Iter) CompilerOption {
+func WithIterFunction(name string, minarity, maxarity int, f func(any, []any) Iter) CompilerOption {
return withFunction(name, minarity, maxarity, true,
- func(v interface{}, args []interface{}) interface{} {
+ func(v any, args []any) any {
return f(v, args)
},
)
}
-func withFunction(name string, minarity, maxarity int, iter bool,
- f func(interface{}, []interface{}) interface{}) CompilerOption {
+func withFunction(name string, minarity, maxarity int, iter bool, f func(any, []any) any) CompilerOption {
if !(0 <= minarity && minarity <= maxarity && maxarity <= 30) {
panic(fmt.Sprintf("invalid arity for %q: %d, %d", name, minarity, maxarity))
}
@@ -74,7 +71,7 @@ func withFunction(name string, minarity, maxarity int, iter bool,
}
c.customFuncs[name] = function{
argcount | fn.argcount, iter,
- func(x interface{}, xs []interface{}) interface{} {
+ func(x any, xs []any) any {
if argcount&(1<<len(xs)) != 0 {
return f(x, xs)
}
diff --git a/option_function_test.go b/option_function_test.go
index 7e4cf55..fe13ff9 100644
--- a/option_function_test.go
+++ b/option_function_test.go
@@ -10,7 +10,7 @@ import (
"github.com/itchyny/gojq"
)
-func toFloat(x interface{}) (float64, bool) {
+func toFloat(x any) (float64, bool) {
switch x := x.(type) {
case int:
return float64(x), true
@@ -31,7 +31,7 @@ func ExampleWithFunction() {
}
code, err := gojq.Compile(
query,
- gojq.WithFunction("f", 0, 1, func(x interface{}, xs []interface{}) interface{} {
+ gojq.WithFunction("f", 0, 1, func(x any, xs []any) any {
if x, ok := toFloat(x); ok {
if len(xs) == 1 {
if y, ok := toFloat(xs[0]); ok {
@@ -50,7 +50,7 @@ func ExampleWithFunction() {
if err != nil {
log.Fatalln(err)
}
- input := []interface{}{0, 1, 2.5, json.Number("10000000000000000000000000000000000000000")}
+ input := []any{0, 1, 2.5, json.Number("10000000000000000000000000000000000000000")}
iter := code.Run(input)
for {
v, ok := iter.Next()
diff --git a/option_iter_function_test.go b/option_iter_function_test.go
index ae005f3..a7ffc77 100644
--- a/option_iter_function_test.go
+++ b/option_iter_function_test.go
@@ -12,7 +12,7 @@ type rangeIter struct {
value, max int
}
-func (iter *rangeIter) Next() (interface{}, bool) {
+func (iter *rangeIter) Next() (any, bool) {
if iter.value >= iter.max {
return nil, false
}
@@ -28,7 +28,7 @@ func ExampleWithIterFunction() {
}
code, err := gojq.Compile(
query,
- gojq.WithIterFunction("f", 2, 2, func(_ interface{}, xs []interface{}) gojq.Iter {
+ gojq.WithIterFunction("f", 2, 2, func(_ any, xs []any) gojq.Iter {
if x, ok := xs[0].(int); ok {
if y, ok := xs[1].(int); ok {
return &rangeIter{x, y}
diff --git a/option_module_loader_test.go b/option_module_loader_test.go
index b978148..7b41d51 100644
--- a/option_module_loader_test.go
+++ b/option_module_loader_test.go
@@ -40,7 +40,7 @@ func ExampleWithModuleLoader() {
if err != nil {
log.Fatalln(err)
}
- input := map[string]interface{}{"foo": 42}
+ input := map[string]any{"foo": 42}
iter := code.Run(input)
for {
v, ok := iter.Next()
diff --git a/option_test.go b/option_test.go
index 512b402..a1bc581 100644
--- a/option_test.go
+++ b/option_test.go
@@ -51,7 +51,7 @@ func TestWithModuleLoaderError(t *testing.T) {
func TestWithModuleLoader_modulemeta(t *testing.T) {
query, err := gojq.Parse(`
- "module1" | modulemeta
+ "module1", "module2" | modulemeta
`)
if err != nil {
t.Fatal(err)
@@ -64,32 +64,42 @@ func TestWithModuleLoader_modulemeta(t *testing.T) {
t.Fatal(err)
}
iter := code.Run(nil)
+ n := 0
for {
got, ok := iter.Next()
if !ok {
break
}
- if expected := map[string]interface{}{
- "deps": []interface{}{
- map[string]interface{}{
- "relpath": "module2",
- "as": "foo",
- "is_data": false,
+ if n == 0 {
+ if expected := map[string]any{
+ "deps": []any{
+ map[string]any{
+ "relpath": "module2",
+ "as": "foo",
+ "is_data": false,
+ },
},
- },
- "name": "module1",
- "test": 42,
- }; !reflect.DeepEqual(got, expected) {
- t.Errorf("expected: %v, got: %v", expected, got)
+ "name": "module1",
+ "test": 42,
+ }; !reflect.DeepEqual(got, expected) {
+ t.Errorf("expected: %v, got: %v", expected, got)
+ }
+ } else {
+ if expected := map[string]any{
+ "deps": []any{}, // not a nil-slice
+ }; !reflect.DeepEqual(got, expected) {
+ t.Errorf("expected: %v, got: %v", expected, got)
+ }
}
+ n++
}
}
type moduleLoaderJSON struct{}
-func (*moduleLoaderJSON) LoadJSON(name string) (interface{}, error) {
+func (*moduleLoaderJSON) LoadJSON(name string) (any, error) {
if name == "module1" {
- return []interface{}{1.0, 42, json.Number("123")}, nil
+ return []any{1.0, 42, json.Number("123")}, nil
}
return nil, fmt.Errorf("module not found: %q", name)
}
@@ -115,7 +125,7 @@ func TestWithModuleLoader_JSON(t *testing.T) {
if !ok {
break
}
- if expected := []interface{}{[]interface{}{1.0, 42, 123}, 5166}; !reflect.DeepEqual(got, expected) {
+ if expected := []any{[]any{1.0, 42, 123}, 5166}; !reflect.DeepEqual(got, expected) {
t.Errorf("expected: %v, got: %v", expected, got)
}
}
@@ -178,7 +188,7 @@ func TestWithEnvironLoader(t *testing.T) {
if !ok {
break
}
- expected := map[string]interface{}{"foo": "42", "bar": "128", "qux": ""}
+ expected := map[string]any{"foo": "42", "bar": "128", "qux": ""}
if !reflect.DeepEqual(got, expected) {
t.Errorf("expected: %v, got: %v", expected, got)
}
@@ -200,7 +210,7 @@ func TestWithEnvironLoaderEmpty(t *testing.T) {
if !ok {
break
}
- if expected := map[string]interface{}{}; !reflect.DeepEqual(got, expected) {
+ if expected := map[string]any{}; !reflect.DeepEqual(got, expected) {
t.Errorf("expected: %v, got: %v", expected, got)
}
}
@@ -287,13 +297,13 @@ func TestWithVariablesError2(t *testing.T) {
func TestWithFunction(t *testing.T) {
options := []gojq.CompilerOption{
- gojq.WithFunction("f", 0, 0, func(x interface{}, _ []interface{}) interface{} {
+ gojq.WithFunction("f", 0, 0, func(x any, _ []any) any {
if x, ok := x.(int); ok {
return x * 2
}
return fmt.Errorf("f cannot be applied to: %v", x)
}),
- gojq.WithFunction("g", 1, 1, func(x interface{}, xs []interface{}) interface{} {
+ gojq.WithFunction("g", 1, 1, func(x any, xs []any) any {
if x, ok := x.(int); ok {
if y, ok := xs[0].(int); ok {
return x + y
@@ -310,7 +320,7 @@ func TestWithFunction(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- iter := code.Run([]interface{}{0, 1, 2, 3, 4})
+ iter := code.Run([]any{0, 1, 2, 3, 4})
n := 0
for {
v, ok := iter.Next()
@@ -354,13 +364,13 @@ func TestWithFunction(t *testing.T) {
func TestWithFunctionDuplicateName(t *testing.T) {
options := []gojq.CompilerOption{
- gojq.WithFunction("f", 0, 0, func(x interface{}, _ []interface{}) interface{} {
+ gojq.WithFunction("f", 0, 0, func(x any, _ []any) any {
if x, ok := x.(int); ok {
return x * 2
}
return fmt.Errorf("f cannot be applied to: %v", x)
}),
- gojq.WithFunction("f", 1, 1, func(x interface{}, xs []interface{}) interface{} {
+ gojq.WithFunction("f", 1, 1, func(x any, xs []any) any {
if x, ok := x.(int); ok {
if y, ok := xs[0].(int); ok {
return x + y
@@ -368,13 +378,13 @@ func TestWithFunctionDuplicateName(t *testing.T) {
}
return fmt.Errorf("f cannot be applied to: %v, %v", x, xs)
}),
- gojq.WithFunction("f", 0, 0, func(x interface{}, _ []interface{}) interface{} {
+ gojq.WithFunction("f", 0, 0, func(x any, _ []any) any {
if x, ok := x.(int); ok {
return x * 4
}
return fmt.Errorf("f cannot be applied to: %v", x)
}),
- gojq.WithFunction("f", 2, 2, func(x interface{}, xs []interface{}) interface{} {
+ gojq.WithFunction("f", 2, 2, func(x any, xs []any) any {
if x, ok := x.(int); ok {
if y, ok := xs[0].(int); ok {
if z, ok := xs[1].(int); ok {
@@ -393,7 +403,7 @@ func TestWithFunctionDuplicateName(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- iter := code.Run([]interface{}{0, 1, 2, 3, 4})
+ iter := code.Run([]any{0, 1, 2, 3, 4})
n := 0
for {
v, ok := iter.Next()
@@ -437,7 +447,7 @@ func TestWithFunctionDuplicateName(t *testing.T) {
func TestWithFunctionMultipleArities(t *testing.T) {
options := []gojq.CompilerOption{
- gojq.WithFunction("f", 0, 4, func(x interface{}, xs []interface{}) interface{} {
+ gojq.WithFunction("f", 0, 4, func(x any, xs []any) any {
if x, ok := x.(int); ok {
x *= 2
for _, y := range xs {
@@ -449,7 +459,7 @@ func TestWithFunctionMultipleArities(t *testing.T) {
}
return fmt.Errorf("f cannot be applied to: %v, %v", x, xs)
}),
- gojq.WithFunction("f", 2, 3, func(x interface{}, xs []interface{}) interface{} {
+ gojq.WithFunction("f", 2, 3, func(x any, xs []any) any {
if x, ok := x.(int); ok {
for _, y := range xs {
if y, ok := y.(int); ok {
@@ -460,7 +470,7 @@ func TestWithFunctionMultipleArities(t *testing.T) {
}
return fmt.Errorf("f cannot be applied to: %v, %v", x, xs)
}),
- gojq.WithFunction("g", 0, 30, func(x interface{}, xs []interface{}) interface{} {
+ gojq.WithFunction("g", 0, 30, func(x any, xs []any) any {
return nil
}),
}
@@ -472,7 +482,7 @@ func TestWithFunctionMultipleArities(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- iter := code.Run([]interface{}{0, 1, 2, 3, 4})
+ iter := code.Run([]any{0, 1, 2, 3, 4})
n := 0
for {
v, ok := iter.Next()
@@ -515,25 +525,25 @@ func TestWithFunctionMultipleArities(t *testing.T) {
}
type valueError struct {
- v interface{}
+ v any
}
func (err *valueError) Error() string {
return "error: " + fmt.Sprint(err.v)
}
-func (err *valueError) Value() interface{} {
+func (err *valueError) Value() any {
return err.v
}
func TestWithFunctionValueError(t *testing.T) {
- expected := map[string]interface{}{"foo": 42}
+ expected := map[string]any{"foo": 42}
query, err := gojq.Parse("try f catch .")
if err != nil {
t.Fatal(err)
}
code, err := gojq.Compile(query,
- gojq.WithFunction("f", 0, 0, func(x interface{}, _ []interface{}) interface{} {
+ gojq.WithFunction("f", 0, 0, func(x any, _ []any) any {
return &valueError{expected}
}),
)
@@ -558,7 +568,7 @@ func TestWithFunctionCompileArgsError(t *testing.T) {
t.Fatal(err)
}
_, err = gojq.Compile(query,
- gojq.WithFunction("f", 0, 1, func(interface{}, []interface{}) interface{} {
+ gojq.WithFunction("f", 0, 1, func(any, []any) any {
return 0
}),
)
@@ -581,7 +591,7 @@ func TestWithFunctionArityError(t *testing.T) {
}
}()
t.Fatal(gojq.Compile(query,
- gojq.WithFunction("f", tc.min, tc.max, func(interface{}, []interface{}) interface{} {
+ gojq.WithFunction("f", tc.min, tc.max, func(any, []any) any {
return 0
}),
))
@@ -595,10 +605,10 @@ func TestWithIterFunction(t *testing.T) {
t.Fatal(err)
}
code, err := gojq.Compile(query,
- gojq.WithIterFunction("f", 0, 0, func(interface{}, []interface{}) gojq.Iter {
+ gojq.WithIterFunction("f", 0, 0, func(any, []any) gojq.Iter {
return gojq.NewIter(1, 2, 3)
}),
- gojq.WithIterFunction("g", 2, 2, func(_ interface{}, xs []interface{}) gojq.Iter {
+ gojq.WithIterFunction("g", 2, 2, func(_ any, xs []any) gojq.Iter {
if x, ok := xs[0].(int); ok {
if y, ok := xs[1].(int); ok {
return &rangeIter{x, y}
@@ -606,7 +616,7 @@ func TestWithIterFunction(t *testing.T) {
}
return gojq.NewIter(fmt.Errorf("g cannot be applied to: %v", xs))
}),
- gojq.WithIterFunction("h", 0, 0, func(interface{}, []interface{}) gojq.Iter {
+ gojq.WithIterFunction("h", 0, 0, func(any, []any) gojq.Iter {
return gojq.NewIter()
}),
)
@@ -636,7 +646,7 @@ func TestWithIterFunctionError(t *testing.T) {
t.Fatal(err)
}
code, err := gojq.Compile(query,
- gojq.WithIterFunction("f", 0, 0, func(interface{}, []interface{}) gojq.Iter {
+ gojq.WithIterFunction("f", 0, 0, func(any, []any) gojq.Iter {
return gojq.NewIter(1, errors.New("error"), 3)
}),
)
@@ -677,7 +687,7 @@ func TestWithIterFunctionPathIndexing(t *testing.T) {
t.Fatal(err)
}
code, err := gojq.Compile(query,
- gojq.WithIterFunction("f", 0, 0, func(interface{}, []interface{}) gojq.Iter {
+ gojq.WithIterFunction("f", 0, 0, func(any, []any) gojq.Iter {
return gojq.NewIter(0, 1, 2)
}),
)
@@ -690,7 +700,7 @@ func TestWithIterFunctionPathIndexing(t *testing.T) {
if !ok {
break
}
- if expected := []interface{}{1, 1, 1}; !reflect.DeepEqual(v, expected) {
+ if expected := []any{1, 1, 1}; !reflect.DeepEqual(v, expected) {
t.Errorf("expected: %v, got: %v", expected, v)
}
}
@@ -702,7 +712,7 @@ func TestWithIterFunctionPathInputValue(t *testing.T) {
t.Fatal(err)
}
code, err := gojq.Compile(query,
- gojq.WithIterFunction("f", 0, 0, func(v interface{}, _ []interface{}) gojq.Iter {
+ gojq.WithIterFunction("f", 0, 0, func(v any, _ []any) gojq.Iter {
return gojq.NewIter(v, v, v)
}),
)
@@ -715,7 +725,7 @@ func TestWithIterFunctionPathInputValue(t *testing.T) {
if !ok {
break
}
- if expected := map[string]interface{}{"x": 1}; !reflect.DeepEqual(v, expected) {
+ if expected := map[string]any{"x": 1}; !reflect.DeepEqual(v, expected) {
t.Errorf("expected: %v, got: %v", expected, v)
}
}
@@ -727,7 +737,7 @@ func TestWithIterFunctionPathEmpty(t *testing.T) {
t.Fatal(err)
}
code, err := gojq.Compile(query,
- gojq.WithIterFunction("f", 0, 0, func(interface{}, []interface{}) gojq.Iter {
+ gojq.WithIterFunction("f", 0, 0, func(any, []any) gojq.Iter {
return gojq.NewIter()
}),
)
@@ -740,7 +750,7 @@ func TestWithIterFunctionPathEmpty(t *testing.T) {
if !ok {
break
}
- if expected := map[string]interface{}{"x": 0}; !reflect.DeepEqual(v, expected) {
+ if expected := map[string]any{"x": 0}; !reflect.DeepEqual(v, expected) {
t.Errorf("expected: %v, got: %v", expected, v)
}
}
@@ -752,8 +762,8 @@ func TestWithIterFunctionInvalidPathError(t *testing.T) {
t.Fatal(err)
}
code, err := gojq.Compile(query,
- gojq.WithIterFunction("f", 0, 0, func(interface{}, []interface{}) gojq.Iter {
- return gojq.NewIter(map[string]interface{}{"x": 1})
+ gojq.WithIterFunction("f", 0, 0, func(any, []any) gojq.Iter {
+ return gojq.NewIter(map[string]any{"x": 1})
}),
)
if err != nil {
@@ -779,7 +789,7 @@ func TestWithIterFunctionPathError(t *testing.T) {
t.Fatal(err)
}
code, err := gojq.Compile(query,
- gojq.WithIterFunction("f", 0, 0, func(interface{}, []interface{}) gojq.Iter {
+ gojq.WithIterFunction("f", 0, 0, func(any, []any) gojq.Iter {
return gojq.NewIter(errors.New("error"))
}),
)
@@ -812,10 +822,10 @@ func TestWithIterFunctionDefineError(t *testing.T) {
}
}()
t.Fatal(gojq.Compile(query,
- gojq.WithFunction("f", 0, 0, func(interface{}, []interface{}) interface{} {
+ gojq.WithFunction("f", 0, 0, func(any, []any) any {
return 0
}),
- gojq.WithIterFunction("f", 0, 0, func(interface{}, []interface{}) gojq.Iter {
+ gojq.WithIterFunction("f", 0, 0, func(any, []any) gojq.Iter {
return gojq.NewIter()
}),
))
@@ -838,7 +848,7 @@ func TestWithFunctionWithModuleLoader(t *testing.T) {
t.Fatal(err)
}
code, err := gojq.Compile(query,
- gojq.WithFunction("f", 0, 0, func(x interface{}, _ []interface{}) interface{} {
+ gojq.WithFunction("f", 0, 0, func(x any, _ []any) any {
if x, ok := x.(int); ok {
return x * 2
}
@@ -849,7 +859,7 @@ func TestWithFunctionWithModuleLoader(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- iter := code.Run([]interface{}{0, 1, 2, 3, 4})
+ iter := code.Run([]any{0, 1, 2, 3, 4})
n := 0
for {
v, ok := iter.Next()
diff --git a/parser.go b/parser.go
index 145a493..1e5e50a 100644
--- a/parser.go
+++ b/parser.go
@@ -38,7 +38,7 @@ func prependFuncDef(xs []*FuncDef, x *FuncDef) []*FuncDef {
//line parser.go.y:33
type yySymType struct {
yys int
- value interface{}
+ value any
token string
operator Operator
}
diff --git a/parser.go.y b/parser.go.y
index e03b14b..380c3cf 100644
--- a/parser.go.y
+++ b/parser.go.y
@@ -31,7 +31,7 @@ func prependFuncDef(xs []*FuncDef, x *FuncDef) []*FuncDef {
%}
%union {
- value interface{}
+ value any
token string
operator Operator
}
diff --git a/preview.go b/preview.go
index 763d510..e082eb5 100644
--- a/preview.go
+++ b/preview.go
@@ -8,18 +8,18 @@ import "unicode/utf8"
//
// This method is used by error messages of built-in operators and functions,
// and accepts only limited types (nil, bool, int, float64, *big.Int, string,
-// []interface{}, and map[string]interface{}). Note that the maximum width and
-// trailing strings on truncation may be changed in the future.
-func Preview(v interface{}) string {
+// []any, and map[string]any). Note that the maximum width and trailing strings
+// on truncation may be changed in the future.
+func Preview(v any) string {
bs := jsonLimitedMarshal(v, 32)
if l := 30; len(bs) > l {
var trailing string
switch v.(type) {
case string:
trailing = ` ..."`
- case []interface{}:
+ case []any:
trailing = " ...]"
- case map[string]interface{}:
+ case map[string]any:
trailing = " ...}"
default:
trailing = " ..."
@@ -33,7 +33,7 @@ func Preview(v interface{}) string {
return string(bs)
}
-func jsonLimitedMarshal(v interface{}, n int) (bs []byte) {
+func jsonLimitedMarshal(v any, n int) (bs []byte) {
w := &limitedWriter{buf: make([]byte, n)}
defer func() {
_ = recover()
@@ -51,7 +51,7 @@ type limitedWriter struct {
func (w *limitedWriter) Write(bs []byte) (int, error) {
n := copy(w.buf[w.off:], bs)
if w.off += n; w.off == len(w.buf) {
- panic(nil)
+ panic(struct{}{})
}
return n, nil
}
@@ -59,7 +59,7 @@ func (w *limitedWriter) Write(bs []byte) (int, error) {
func (w *limitedWriter) WriteByte(b byte) error {
w.buf[w.off] = b
if w.off++; w.off == len(w.buf) {
- panic(nil)
+ panic(struct{}{})
}
return nil
}
@@ -67,7 +67,7 @@ func (w *limitedWriter) WriteByte(b byte) error {
func (w *limitedWriter) WriteString(s string) (int, error) {
n := copy(w.buf[w.off:], s)
if w.off += n; w.off == len(w.buf) {
- panic(nil)
+ panic(struct{}{})
}
return n, nil
}
diff --git a/preview_test.go b/preview_test.go
index 29af6e8..5b6c878 100644
--- a/preview_test.go
+++ b/preview_test.go
@@ -11,7 +11,7 @@ import (
func TestPreview(t *testing.T) {
testCases := []struct {
- value interface{}
+ value any
expected string
}{
{
@@ -71,35 +71,35 @@ func TestPreview(t *testing.T) {
`"01234567 ..."`,
},
{
- []interface{}{},
+ []any{},
"[]",
},
{
- []interface{}{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
+ []any{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
"[0,1,2,3,4,5,6,7,8,9,10,11,12]",
},
{
- []interface{}{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
+ []any{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
"[0,1,2,3,4,5,6,7,8,9,10,1 ...]",
},
{
- []interface{}{[]interface{}{[]interface{}{[]interface{}{[]interface{}{[]interface{}{[]interface{}{[]interface{}{nil, nil, nil}}}}}}}},
+ []any{[]any{[]any{[]any{[]any{[]any{[]any{[]any{nil, nil, nil}}}}}}}},
"[[[[[[[[null,null,null]]]]]]]]",
},
{
- []interface{}{[]interface{}{[]interface{}{[]interface{}{[]interface{}{[]interface{}{[]interface{}{[]interface{}{nil, nil, nil, nil}}}}}}}},
+ []any{[]any{[]any{[]any{[]any{[]any{[]any{[]any{nil, nil, nil, nil}}}}}}}},
"[[[[[[[[null,null,null,nu ...]",
},
{
- map[string]interface{}{},
+ map[string]any{},
"{}",
},
{
- map[string]interface{}{"0": map[string]interface{}{"1": map[string]interface{}{"2": map[string]interface{}{"3": []interface{}{nil}}}}},
+ map[string]any{"0": map[string]any{"1": map[string]any{"2": map[string]any{"3": []any{nil}}}}},
`{"0":{"1":{"2":{"3":[null]}}}}`,
},
{
- map[string]interface{}{"0": map[string]interface{}{"1": map[string]interface{}{"2": map[string]interface{}{"3": map[string]interface{}{"4": map[string]interface{}{}}}}}},
+ map[string]any{"0": map[string]any{"1": map[string]any{"2": map[string]any{"3": map[string]any{"4": map[string]any{}}}}}},
`{"0":{"1":{"2":{"3":{"4": ...}`,
},
}
diff --git a/query.go b/query.go
index 4bba2d2..5f20b4f 100644
--- a/query.go
+++ b/query.go
@@ -21,12 +21,12 @@ type Query struct {
//
// It is safe to call this method in goroutines, to reuse a parsed [*Query].
// But for arguments, do not give values sharing same data between goroutines.
-func (e *Query) Run(v interface{}) Iter {
+func (e *Query) Run(v any) Iter {
return e.RunWithContext(context.Background(), v)
}
// RunWithContext runs the query with context.
-func (e *Query) RunWithContext(ctx context.Context, v interface{}) Iter {
+func (e *Query) RunWithContext(ctx context.Context, v any) Iter {
code, err := Compile(e)
if err != nil {
return NewIter(err)
@@ -92,14 +92,14 @@ func (e *Query) minify() {
}
}
-func (e *Query) toIndexKey() interface{} {
+func (e *Query) toIndexKey() any {
if e.Term == nil {
return nil
}
return e.Term.toIndexKey()
}
-func (e *Query) toIndices(xs []interface{}) []interface{} {
+func (e *Query) toIndices(xs []any) []any {
if e.Term == nil {
return nil
}
@@ -314,7 +314,7 @@ func (e *Term) toFunc() string {
}
}
-func (e *Term) toIndexKey() interface{} {
+func (e *Term) toIndexKey() any {
switch e.Type {
case TermTypeNumber:
return toNumber(e.Number)
@@ -330,7 +330,7 @@ func (e *Term) toIndexKey() interface{} {
}
}
-func (e *Term) toIndices(xs []interface{}) []interface{} {
+func (e *Term) toIndices(xs []any) []any {
switch e.Type {
case TermTypeIndex:
if xs = e.Index.toIndices(xs); xs == nil {
@@ -351,7 +351,7 @@ func (e *Term) toIndices(xs []interface{}) []interface{} {
return xs
}
-func (e *Term) toNumber() interface{} {
+func (e *Term) toNumber() any {
if e.Type == TermTypeNumber {
return toNumber(e.Number)
}
@@ -379,7 +379,7 @@ func (e *Unary) minify() {
e.Term.minify()
}
-func (e *Unary) toNumber() interface{} {
+func (e *Unary) toNumber() any {
v := e.Term.toNumber()
if v != nil && e.Op == OpSub {
v = funcOpNegate(v)
@@ -514,7 +514,7 @@ func (e *Index) minify() {
}
}
-func (e *Index) toIndexKey() interface{} {
+func (e *Index) toIndexKey() any {
if e.Name != "" {
return e.Name
} else if e.Str != nil {
@@ -524,7 +524,7 @@ func (e *Index) toIndexKey() interface{} {
} else if !e.IsSlice {
return e.Start.toIndexKey()
} else {
- var start, end interface{}
+ var start, end any
ok := true
if e.Start != nil {
start = e.Start.toIndexKey()
@@ -535,13 +535,13 @@ func (e *Index) toIndexKey() interface{} {
ok = end != nil
}
if ok {
- return map[string]interface{}{"start": start, "end": end}
+ return map[string]any{"start": start, "end": end}
}
}
return nil
}
-func (e *Index) toIndices(xs []interface{}) []interface{} {
+func (e *Index) toIndices(xs []any) []any {
if k := e.toIndexKey(); k != nil {
return append(xs, k)
}
@@ -795,7 +795,7 @@ func (e *Suffix) toTerm() *Term {
}
}
-func (e *Suffix) toIndices(xs []interface{}) []interface{} {
+func (e *Suffix) toIndices(xs []any) []any {
if e.Index == nil {
return nil
}
@@ -1057,7 +1057,7 @@ func (e *ConstTerm) writeTo(s *strings.Builder) {
}
}
-func (e *ConstTerm) toValue() interface{} {
+func (e *ConstTerm) toValue() any {
if e.Object != nil {
return e.Object.ToValue()
} else if e.Array != nil {
@@ -1101,12 +1101,12 @@ func (e *ConstObject) writeTo(s *strings.Builder) {
s.WriteString(" }")
}
-// ToValue converts the object to map[string]interface{}.
-func (e *ConstObject) ToValue() map[string]interface{} {
+// ToValue converts the object to map[string]any.
+func (e *ConstObject) ToValue() map[string]any {
if e == nil {
return nil
}
- v := make(map[string]interface{}, len(e.KeyVals))
+ v := make(map[string]any, len(e.KeyVals))
for _, e := range e.KeyVals {
key := e.Key
if key == "" {
@@ -1162,8 +1162,8 @@ func (e *ConstArray) writeTo(s *strings.Builder) {
s.WriteByte(']')
}
-func (e *ConstArray) toValue() []interface{} {
- v := make([]interface{}, len(e.Elems))
+func (e *ConstArray) toValue() []any {
+ v := make([]any, len(e.Elems))
for i, e := range e.Elems {
v[i] = e.toValue()
}
diff --git a/query_test.go b/query_test.go
index 9a71be4..87c4b52 100644
--- a/query_test.go
+++ b/query_test.go
@@ -23,7 +23,7 @@ func ExampleQuery_Run() {
if err != nil {
log.Fatalln(err)
}
- input := map[string]interface{}{"foo": []interface{}{1, 2, 3}}
+ input := map[string]any{"foo": []any{1, 2, 3}}
iter := query.Run(input)
for {
v, ok := iter.Next()
@@ -72,7 +72,7 @@ func TestQueryRun_Errors(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- iter := query.Run([]interface{}{0, 1, 2, 3, 4})
+ iter := query.Run([]any{0, 1, 2, 3, 4})
n := 0
for {
v, ok := iter.Next()
@@ -98,7 +98,7 @@ func TestQueryRun_ObjectError(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- iter := query.Run([]interface{}{0, "x", []interface{}{}})
+ iter := query.Run([]any{0, "x", []any{}})
for {
v, ok := iter.Next()
if !ok {
@@ -109,7 +109,7 @@ func TestQueryRun_ObjectError(t *testing.T) {
if !strings.Contains(err.Error(), expected) {
t.Errorf("expected: %v, got: %v", expected, err)
}
- } else if expected := map[string]interface{}{"x": 1}; !reflect.DeepEqual(v, expected) {
+ } else if expected := map[string]any{"x": 1}; !reflect.DeepEqual(v, expected) {
t.Errorf("expected: %v, got: %v", expected, v)
}
}
@@ -120,7 +120,7 @@ func TestQueryRun_IndexError(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- iter := query.Run([]interface{}{0})
+ iter := query.Run([]any{0})
for {
v, ok := iter.Next()
if !ok {
@@ -196,7 +196,7 @@ func TestQueryRun_Strings(t *testing.T) {
if err, ok := v.(error); ok {
t.Fatal(err)
}
- if expected := []interface{}{
+ if expected := []any{
0x00, int('\\'), 0x1f, int('"'), int('\n'), int('\n'), int('\n'),
int('\n'), int('\n'), int('\n'), int('/'), 0x7f, 0xfffd, 128516,
}; !reflect.DeepEqual(v, expected) {
@@ -210,7 +210,7 @@ func TestQueryRun_NumericTypes(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- iter := query.Run([]interface{}{
+ iter := query.Run([]any{
int64(1), int32(1), int16(1), int8(1), uint64(1), uint32(1), uint16(1), uint8(1), uint(math.MaxUint),
int64(math.MaxInt64), int64(math.MinInt64), uint64(math.MaxUint64), uint32(math.MaxUint32),
new(big.Int).SetUint64(math.MaxUint64), new(big.Int).SetUint64(math.MaxUint32),
@@ -250,6 +250,32 @@ func TestQueryRun_Input(t *testing.T) {
}
}
+func TestQueryRun_NonNilSlice(t *testing.T) {
+ for _, f := range []string{"keys", "map(.)", "to_entries", "arrays",
+ "reverse", "flatten", "sort", "sort_by(.)", "group_by(.)", "unique",
+ "unique_by(.)", "transpose", "nth(.)", "indices([])", "path(.)"} {
+ t.Run(f, func(t *testing.T) {
+ query, err := gojq.Parse("[] | " + f)
+ if err != nil {
+ t.Fatal(err)
+ }
+ iter := query.Run(nil)
+ for {
+ v, ok := iter.Next()
+ if !ok {
+ break
+ }
+ if err, ok := v.(error); ok {
+ t.Fatal(err)
+ }
+ if expected := []any{}; !reflect.DeepEqual(v, expected) {
+ t.Errorf("expected: %#v, got: %#v", expected, v)
+ }
+ }
+ })
+ }
+}
+
func TestQueryRun_Race(t *testing.T) {
query, err := gojq.Parse("range(10)")
if err != nil {
@@ -327,3 +353,27 @@ func BenchmarkParse(b *testing.B) {
}
}
}
+
+func FuzzQueryRun(f *testing.F) {
+ f.Fuzz(func(t *testing.T, src string) {
+ if len(src) > 16 {
+ t.SkipNow()
+ }
+ q, err := gojq.Parse(src)
+ if err != nil {
+ t.SkipNow()
+ }
+ code, err := gojq.Compile(q)
+ if err != nil {
+ t.SkipNow()
+ }
+ ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
+ t.Cleanup(cancel)
+ iter := code.RunWithContext(ctx, nil)
+ for {
+ if _, ok := iter.Next(); !ok {
+ break
+ }
+ }
+ })
+}
diff --git a/release.go b/release.go
index 1144485..c34dfb4 100644
--- a/release.go
+++ b/release.go
@@ -5,7 +5,7 @@ package gojq
type codeinfo struct{}
-func (c *compiler) appendCodeInfo(interface{}) {}
+func (c *compiler) appendCodeInfo(any) {}
func (c *compiler) deleteCodeInfo(string) {}
diff --git a/stack.go b/stack.go
index 50445fc..a0e265c 100644
--- a/stack.go
+++ b/stack.go
@@ -7,7 +7,7 @@ type stack struct {
}
type block struct {
- value interface{}
+ value any
next int
}
@@ -15,7 +15,7 @@ func newStack() *stack {
return &stack{index: -1, limit: -1}
}
-func (s *stack) push(v interface{}) {
+func (s *stack) push(v any) {
b := block{v, s.index}
i := s.index + 1
if i <= s.limit {
@@ -29,13 +29,13 @@ func (s *stack) push(v interface{}) {
}
}
-func (s *stack) pop() interface{} {
+func (s *stack) pop() any {
b := s.data[s.index]
s.index = b.next
return b.value
}
-func (s *stack) top() interface{} {
+func (s *stack) top() any {
return s.data[s.index].value
}
diff --git a/type.go b/type.go
index 578a6f4..bb388e2 100644
--- a/type.go
+++ b/type.go
@@ -8,9 +8,8 @@ import (
// TypeOf returns the jq-flavored type name of v.
//
// This method is used by built-in type/0 function, and accepts only limited
-// types (nil, bool, int, float64, *big.Int, string, []interface{},
-// and map[string]interface{}).
-func TypeOf(v interface{}) string {
+// types (nil, bool, int, float64, *big.Int, string, []any, and map[string]any).
+func TypeOf(v any) string {
switch v.(type) {
case nil:
return "null"
@@ -20,9 +19,9 @@ func TypeOf(v interface{}) string {
return "number"
case string:
return "string"
- case []interface{}:
+ case []any:
return "array"
- case map[string]interface{}:
+ case map[string]any:
return "object"
default:
panic(fmt.Sprintf("invalid type: %[1]T (%[1]v)", v))
diff --git a/type_test.go b/type_test.go
index c3da1cf..ef917a0 100644
--- a/type_test.go
+++ b/type_test.go
@@ -11,7 +11,7 @@ import (
func TestTypeOf(t *testing.T) {
testCases := []struct {
- value interface{}
+ value any
expected string
}{
{nil, "null"},
@@ -24,8 +24,8 @@ func TestTypeOf(t *testing.T) {
{math.Inf(-1), "number"},
{big.NewInt(10), "number"},
{"string", "string"},
- {[]interface{}{}, "array"},
- {map[string]interface{}{}, "object"},
+ {[]any{}, "array"},
+ {map[string]any{}, "object"},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%v", tc.value), func(t *testing.T) {
More details
Historical runs
- failed: src/github.com/rivo/uniseg/properties.go:137:20: error: expected ‘(’
- success: Merged new upstream version 0.12.11
- failed: src/github.com/rivo/uniseg/properties.go:137:20: error: expected ‘(’
- nothing-to-do: Last upstream version 0.12.7 already imported. Import a snapshot by specifying --snapshot.