diff --git a/.circleci/config.yml b/.circleci/config.yml
deleted file mode 100644
index 96472bc882..0000000000
--- a/.circleci/config.yml
+++ /dev/null
@@ -1,213 +0,0 @@
-version: 2
-jobs:
- deps:
- docker:
- - image: circleci/golang:1.14
- working_directory: /home/circleci/.go_workspace/src/github.com/loadimpact/k6
- steps:
- - checkout
- - run:
- name: Check dependencies
- command: |
- go version
- test -z "$(go mod vendor && git status --porcelain)"
- go mod verify
-
- lint:
- docker:
- - image: circleci/golang:1.14
- environment:
- GOLANGCI_VERSION: v1.30.0
- GO111MODULE: 'on'
- working_directory: /home/circleci/.go_workspace/src/github.com/loadimpact/k6
- steps:
- # Workaround for custom env vars not available in cache keys
- # https://discuss.circleci.com/t/cannot-use-circle-yml-environment-variables-in-cache-keys/10994/8
- - run: echo $GOLANGCI_VERSION > /tmp/.golangci.version
- - restore_cache:
- name: Restore golangci-lint cache
- key: golangci-lint-{{ arch }}-{{ checksum "/tmp/.golangci.version" }}-{{ .Environment.CACHE_VERSION }}
- paths:
- - /go/bin/golangci-lint
- - run:
- name: Install golangci-lint
- command: |
- command -v golangci-lint && exit
- go get github.com/golangci/golangci-lint/cmd/golangci-lint@$GOLANGCI_VERSION
- - save_cache:
- name: Save golangci-lint cache
- key: golangci-lint-{{ arch }}-{{ checksum "/tmp/.golangci.version" }}-{{ .Environment.CACHE_VERSION }}
- paths:
- - /go/bin/golangci-lint
- - checkout
- - run:
- name: Run golangci-lint
- command: |
- BASEREV=$(git merge-base HEAD origin/master)
- echo "Base revision: $BASEREV"
- golangci-lint run --out-format=tab --new-from-rev "$BASEREV" ./...
-
-
- test:
- docker:
- - image: circleci/golang:1.14
- environment:
- GOPATH: /home/circleci/.go_workspace
- working_directory: /home/circleci/.go_workspace/src/github.com/loadimpact/k6
- steps:
- - checkout
- - run:
- name: Run tests and code coverage
- command: |
- go version
- export GOMAXPROCS=2
- export PATH=$GOPATH/bin:$PATH
- echo "mode: set" > coverage.txt
- for pkg in $(go list ./... | grep -v vendor); do
- list=$(go list -test -f '{{ join .Deps "\n"}}' $pkg | grep github.com/loadimpact/k6 | grep -v vendor || true)
- if [ -n "$list" ]; then
- list=$(echo "$list" | cut -f1 -d ' ' | sort -u | paste -sd,)
- fi
-
- go test -race -timeout 800s --coverpkg="$list" -coverprofile=$(echo $pkg | tr / -).coverage $pkg
- done
- grep -h -v "^mode:" *.coverage >> coverage.txt
- rm -f *.coverage
- bash <(curl --fail -s https://codecov.io/bash)
-
- #TODO: when we officially move to Go 1.15, re-enable test-prev-golang with 1.14
-
- test-next-golang:
- docker:
- - image: circleci/golang:1.15
- working_directory: /home/circleci/.go_workspace/src/github.com/loadimpact/k6
- steps:
- - checkout
- - run:
- name: Run tests with next Go version
- command: |
- go version
- export GOMAXPROCS=2
- export PATH=$GOPATH/bin:$PATH
- go test -p 2 -race -timeout 800s ./...
-
- build-docker-images:
- docker:
- - image: circleci/golang:1.14
- working_directory: /home/circleci/.go_workspace/src/github.com/loadimpact/k6
- steps:
- - checkout
- - setup_remote_docker
- - run:
- name: Setup repo and docker
- command: |
- docker info
- echo "{\"https://index.docker.io/v1/\":{\"auth\":\"$DOCKER_AUTH\",\"email\":\"$DOCKER_EMAIL\"}}" >~/.dockercfg
- - run:
- name: Build application Docker image
- command: |
- docker build -t loadimpact/k6 .
- - run:
- name: Run tests on generated Docker image
- command: |
- docker run loadimpact/k6 --help
- docker run loadimpact/k6 help
- docker run loadimpact/k6 run --help
- docker run loadimpact/k6 inspect --help
- docker run loadimpact/k6 status --help
- docker run loadimpact/k6 stats --help
- docker run loadimpact/k6 scale --help
- docker run loadimpact/k6 pause --help
- docker run loadimpact/k6 resume --help
- - deploy:
- name: Push application Docker image
- command: |
- if [ "${CIRCLE_BRANCH}" == "master" ]; then
- docker tag loadimpact/k6 loadimpact/k6:master
- docker push loadimpact/k6:master
- elif [[ "${CIRCLE_TAG}" =~ ^v[0-9]+(\.[0-9]+)*$ ]]; then
- docker tag loadimpact/k6 loadimpact/k6:${CIRCLE_TAG:1}
- docker push loadimpact/k6:latest
- docker push loadimpact/k6:${CIRCLE_TAG:1}
- fi
-
- build-linux-packages:
- docker:
- - image: circleci/golang:1.14
- environment:
- GOPATH: /home/circleci/.go_workspace
- working_directory: /home/circleci/.go_workspace/src/github.com/loadimpact/k6
- steps:
- - checkout
- - run:
- name: Build linux packages
- command: |
- export PATH=$GOPATH/bin:$PATH
-
- go get github.com/Masterminds/glide
- go get -d github.com/mh-cbon/go-bin-deb \
- && cd $GOPATH/src/github.com/mh-cbon/go-bin-deb \
- && glide install \
- && go install
-
- go get -d github.com/mh-cbon/go-bin-rpm \
- && cd $GOPATH/src/github.com/mh-cbon/go-bin-rpm \
- && glide install \
- && go install
-
- sudo apt-get update -y
- sudo apt-get install -y fakeroot rpm
-
- cd $GOPATH/src/github.com/loadimpact/k6
-
- echo "Building k6..."
- CGO_ENABLED=0 GOARCH=amd64 go build -a -trimpath -ldflags "-s -w -X github.com/loadimpact/k6/lib/consts.VersionDetails=$(date -u +"%FT%T%z")/$(git describe --always --long --dirty)" -o /tmp/k6
- echo "Done!"
-
- VERSION=${CIRCLE_TAG:1} ./packaging/gen-packages.sh
-
- - deploy:
- name: Publish packages in Bintray
- command: |
- export VERSION=${CIRCLE_TAG:1}
- # Publishing deb
- curl --fail -H "X-GPG-PASSPHRASE: $GPG_PASSPHRASE" -T dist/k6-v$VERSION-amd64.deb "https://$BINTRAY_USER:$BINTRAY_KEY@api.bintray.com/content/loadimpact/deb/k6/$VERSION/k6-v$VERSION-amd64.deb;deb_distribution=stable;deb_component=main;deb_architecture=amd64;publish=1;override=1"
- # Publishing rpm
- curl --fail -H "X-GPG-PASSPHRASE: $GPG_PASSPHRASE" -T dist/k6-v$VERSION-amd64.rpm "https://$BINTRAY_USER:$BINTRAY_KEY@api.bintray.com/content/loadimpact/rpm/k6/$VERSION/k6-v$VERSION-amd64.rpm?publish=1&override=1"
-
-
-workflows:
- version: 2
- test_and_build:
- jobs:
- - deps:
- filters:
- tags:
- only: /.*/
- - lint
- - test:
- filters:
- tags:
- only: /.*/
- - test-next-golang:
- filters:
- tags:
- only: /.*/
- - build-docker-images:
- requires:
- - deps
- - lint
- - test
- filters:
- tags:
- only: /.*/
- - build-linux-packages:
- requires:
- - deps
- - lint
- - test
- filters:
- branches:
- ignore: /.*/
- tags:
- only: /^v.*/
diff --git a/.codecov.yaml b/.codecov.yaml
index 9317ff3cbc..b27d150245 100644
--- a/.codecov.yaml
+++ b/.codecov.yaml
@@ -4,3 +4,13 @@ coverage:
default:
target: auto
threshold: 0.3%
+ windows:
+ target: auto
+ flags: [windows]
+ ubuntu:
+ target: auto
+ flags: [ubuntu]
+
+flags:
+ windows:
+ ubuntu:
diff --git a/.github/workflows/all.yml b/.github/workflows/all.yml
new file mode 100644
index 0000000000..724afd4308
--- /dev/null
+++ b/.github/workflows/all.yml
@@ -0,0 +1,325 @@
+name: CI
+on:
+ # Enable manually triggering this workflow via the API or web UI
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ tags:
+ - v*
+ pull_request:
+
+defaults:
+ run:
+ shell: bash
+
+env:
+ APP_NAME: "k6"
+ DOCKER_IMAGE_ID: ${{ github.repository }}
+
+jobs:
+ # deps:
+ # runs-on: ubuntu-latest
+ # steps:
+ # - name: Checkout code
+ # uses: actions/checkout@v2
+ # - name: Install Go
+ # uses: actions/setup-go@v2
+ # with:
+ # go-version: 1.14.x
+ # - name: Check dependencies
+ # run: |
+ # go version
+ # test -z "$(go mod vendor && git status --porcelain)"
+ # go mod verify
+
+ # lint:
+ # runs-on: ubuntu-latest
+ # env:
+ # GOLANGCI_VERSION: v1.31
+ # GO111MODULE: 'on'
+ # steps:
+ # - name: Checkout code
+ # uses: actions/checkout@v2
+ # with:
+ # fetch-depth: 0
+ # - name: Install Go
+ # uses: actions/setup-go@v2
+ # with:
+ # go-version: 1.14.x
+ # - name: Install golangci-lint
+ # working-directory: /tmp
+ # run: go get github.com/golangci/golangci-lint/cmd/golangci-lint@$GOLANGCI_VERSION
+ # - name: Run linters
+ # run: |
+ # BASEREV=$(git merge-base HEAD origin/master)
+ # echo "Base revision: $BASEREV"
+ # golangci-lint run --out-format=tab --new-from-rev "$BASEREV" ./...
+
+ # test:
+ # strategy:
+ # matrix:
+ # go-version: [1.14.x]
+ # platform: [ubuntu-latest, windows-latest]
+ # runs-on: ${{ matrix.platform }}
+ # steps:
+ # - name: Checkout code
+ # uses: actions/checkout@v2
+ # - name: Install Go
+ # uses: actions/setup-go@v2
+ # with:
+ # go-version: ${{ matrix.go-version }}
+ # - name: Run tests
+ # run: |
+ # set -x
+ # go version
+ # export GOMAXPROCS=2
+ # args=("-p" "2" "-race")
+ # # Run with less concurrency on Windows to minimize flakiness.
+ # if [[ "${{ matrix.platform }}" == windows* ]]; then
+ # unset args[2]
+ # args[1]="1"
+ # export GOMAXPROCS=1
+ # fi
+ # go test "${args[@]}" -timeout 800s ./...
+
+ # test-cov:
+ # strategy:
+ # matrix:
+ # go-version: [1.15.x]
+ # platform: [ubuntu-latest, windows-latest]
+ # runs-on: ${{ matrix.platform }}
+ # env:
+ # CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ # steps:
+ # - name: Checkout code
+ # uses: actions/checkout@v2
+ # - name: Install Go
+ # uses: actions/setup-go@v2
+ # with:
+ # go-version: ${{ matrix.go-version }}
+ # - name: Run tests with code coverage
+ # run: |
+ # go version
+ # export GOMAXPROCS=2
+ # args=("-p" "2" "-race")
+ # # Run with less concurrency on Windows to minimize flakiness.
+ # if [[ "${{ matrix.platform }}" == windows* ]]; then
+ # unset args[2]
+ # args[1]="1"
+ # export GOMAXPROCS=1
+ # fi
+ # echo "mode: set" > coverage.txt
+ # for pkg in $(go list ./... | grep -v vendor); do
+ # list=$(go list -test -f '{{ join .Deps "\n"}}' $pkg | grep github.com/loadimpact/k6 | grep -v vendor || true)
+ # if [ -n "$list" ]; then
+ # list=$(echo "$list" | cut -f1 -d ' ' | sort -u | paste -sd, -)
+ # fi
+
+ # go test "${args[@]}" -timeout 800s --coverpkg="$list" -coverprofile=$(echo $pkg | tr / -).coverage $pkg
+ # done
+ # grep -h -v "^mode:" *.coverage >> coverage.txt
+ # rm -f *.coverage
+ # - name: Upload coverage to Codecov
+ # run: |
+ # platform="${{ matrix.platform }}"
+ # bash <(curl --fail -s https://codecov.io/bash) -F "${platform%%-*}"
+ # - name: Generate coverage HTML report
+ # run: go tool cover -html=coverage.txt -o coverage.html
+ # - name: Upload coverage report
+ # uses: actions/upload-artifact@v2
+ # with:
+ # name: test-coverage-report-${{ matrix.platform }}
+ # path: coverage.html
+ # retention-days: 7
+
+ configure:
+ runs-on: ubuntu-latest
+ if: startsWith(github.ref, 'refs/tags/v')
+ outputs:
+ version: ${{ steps.get_version.outputs.version }}
+ steps:
+ - name: Get version
+ id: get_version
+ run: |
+ VERSION="${GITHUB_REF##*/}"
+ echo "VERSION=${VERSION}"
+ echo "::set-output name=version::${VERSION}"
+
+ build:
+ runs-on: ubuntu-latest
+ #needs: [deps, lint, test, test-cov]
+ if: startsWith(github.ref, 'refs/tags/v')
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ - name: Install Go
+ uses: actions/setup-go@v2
+ with:
+ go-version: 1.14.x
+ - name: Install package builders
+ env:
+ GO111MODULE: 'off'
+ run: |
+ gopath="$(go env GOPATH)"
+ go get github.com/Masterminds/glide
+ go get -d github.com/mh-cbon/go-bin-deb \
+ && (cd "$gopath/src/github.com/mh-cbon/go-bin-deb" \
+ && glide install \
+ && go install)
+ go get -d github.com/mh-cbon/go-bin-rpm \
+ && (cd "$gopath/src/github.com/mh-cbon/go-bin-rpm" \
+ && glide install \
+ && go install)
+ sudo apt-get update -y
+ sudo apt-get install -y fakeroot rpm
+ - name: Build
+ run: |
+ go version
+ ./build-release.sh
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v2
+ with:
+ name: binaries
+ path: dist/
+ retention-days: 7
+
+ # publish-docker:
+ # runs-on: ubuntu-latest
+ # needs: [deps, lint, test, test-cov, configure]
+ # env:
+ # VERSION: ${{ needs.configure.outputs.version }}
+ # steps:
+ # - name: Checkout code
+ # uses: actions/checkout@v2
+ # - name: Build
+ # run: docker build -t $DOCKER_IMAGE_ID .
+ # - name: Check
+ # run: |
+ # docker run $DOCKER_IMAGE_ID version
+ # docker run $DOCKER_IMAGE_ID --help
+ # docker run $DOCKER_IMAGE_ID help
+ # docker run $DOCKER_IMAGE_ID run --help
+ # docker run $DOCKER_IMAGE_ID inspect --help
+ # docker run $DOCKER_IMAGE_ID status --help
+ # docker run $DOCKER_IMAGE_ID stats --help
+ # docker run $DOCKER_IMAGE_ID scale --help
+ # docker run $DOCKER_IMAGE_ID pause --help
+ # docker run $DOCKER_IMAGE_ID resume --help
+ # - name: Publish
+ # if: github.event_name != 'pull_request'
+ # run: |
+ # echo "REF=${{ github.ref }}"
+ # echo "DOCKER_IMAGE_ID=$DOCKER_IMAGE_ID"
+ # # Log into registry
+ # echo "${{ secrets.DOCKER_PASS }}" | docker login -u "${{ secrets.DOCKER_USER }}" --password-stdin
+ # VERSION="${VERSION#v}"
+ # echo "VERSION=$VERSION"
+ # docker tag "$DOCKER_IMAGE_ID" "$DOCKER_IMAGE_ID:$VERSION"
+ # docker push "$DOCKER_IMAGE_ID:$VERSION"
+ # # We also want to tag the latest stable version as latest
+ # if [[ "$VERSION" != "master" ]] && [[ ! "$VERSION" =~ (RC|rc) ]]; then
+ # docker tag "$DOCKER_IMAGE_ID" "$DOCKER_IMAGE_ID:latest"
+ # docker push "$DOCKER_IMAGE_ID:latest"
+ # fi
+
+ publish-github:
+ runs-on: ubuntu-latest
+ #needs: [deps, lint, test, test-cov, configure, build]
+ needs: [configure, build]
+ if: startsWith(github.ref, 'refs/tags/v')
+ env:
+ VERSION: ${{ needs.configure.outputs.version }}
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ - name: Download binaries
+ uses: actions/download-artifact@v2
+ with:
+ name: binaries
+ path: dist
+ - name: Create release
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ set -x
+ assets=()
+ for asset in ./dist/*; do
+ assets+=("-a" "$asset")
+ done
+ hub release create "${assets[@]}" -m "$VERSION" -m "$(cat ./release\ notes/${VERSION}.md)" "$VERSION"
+ - name: Upload packages to Bintray
+ run: |
+ # Publishing deb
+ curl --fail -H "X-GPG-PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}" -T "dist/k6-$VERSION-amd64.deb" \
+ "https://${{ secrets.BINTRAY_USER }}:${{ secrets.BINTRAY_KEY }}@api.bintray.com/content/imiric2/deb/k6/${VERSION#v}/k6-${VERSION}-amd64.deb;deb_distribution=stable;deb_component=main;deb_architecture=amd64;publish=1;override=1"
+ # Publishing rpm
+ curl --fail -H "X-GPG-PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}" -T "dist/k6-$VERSION-amd64.rpm" \
+ "https://${{ secrets.BINTRAY_USER }}:${{ secrets.BINTRAY_KEY }}@api.bintray.com/content/imiric2/rpm/k6/${VERSION#v}/k6-${VERSION}-amd64.rpm?publish=1&override=1"
+
+ publish-windows:
+ runs-on: windows-latest
+ defaults:
+ run:
+ shell: powershell
+ #needs: [deps, lint, test, test-cov, configure, build]
+ needs: [configure, build]
+ if: startsWith(github.ref, 'refs/tags/v')
+ env:
+ VERSION: ${{ needs.configure.outputs.version }}
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ - name: Install pandoc
+ uses: crazy-max/ghaction-chocolatey@b6061d587628735be315d74358228b83a7dba9a7
+ with:
+ args: install -y pandoc
+ - name: Install wix tools
+ run: |
+ curl -O wix311-binaries.zip https://github.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip
+ Expand-Archive -Path .\wix311-binaries.zip -DestinationPath .\wix311\
+ echo "$pwd\wix311" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
+ - name: Download binaries
+ uses: actions/download-artifact@v2
+ with:
+ name: binaries
+ path: dist
+ - name: Unzip Windows binary
+ run: |
+ Expand-Archive -Path ".\dist\k6-$env:VERSION-win64.zip" -DestinationPath .\packaging\
+ move .\packaging\k6-$env:VERSION-win64\k6.exe .\packaging\
+ rmdir .\packaging\k6-$env:VERSION-win64\
+ - name: Create MSI package
+ run: |
+ $env:VERSION = $env:VERSION -replace 'v(\d+\.\d+\.\d+).*','$1'
+ pandoc -s -f markdown -t rtf -o packaging\LICENSE.rtf LICENSE.md
+ cd .\packaging
+ candle.exe -arch x64 "-dVERSION=$env:VERSION" k6.wxs
+ light.exe -ext WixUIExtension k6.wixobj
+ - name: Prepare Chocolatey package
+ run: |
+ $env:VERSION = $env:VERSION.TrimStart("v", " ")
+ cd .\packaging
+ (Get-Content '.\k6.portable.nuspec' -Raw).Replace("__REPLACE__", "$env:VERSION") | Out-File '.\k6.portable.nuspec'
+ - name: Create Chocolatey package
+ uses: crazy-max/ghaction-chocolatey@b6061d587628735be315d74358228b83a7dba9a7
+ with:
+ args: pack --verbose --outputdirectory .\packaging .\packaging\k6.portable.nuspec
+ - name: Upload packages to Bintray
+ run: |
+ cd .\packaging
+ $env:VERSION = $env:VERSION.TrimStart("v", " ")
+ curl.exe --fail -H "X-GPG-PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}" -T .\k6.msi "https://${{ secrets.BINTRAY_USER }}:${{ secrets.BINTRAY_KEY }}@api.bintray.com/content/imiric2/windows/k6/$env:VERSION/k6-v$env:VERSION-amd64.msi?publish=1&override=1"
+ curl.exe --fail -H "X-GPG-PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}" -T .\k6.portable.$env:VERSION.nupkg "https://${{ secrets.BINTRAY_USER }}:${{ secrets.BINTRAY_KEY }}@api.bintray.com/content/imiric2/choco/k6.portable/$env:VERSION/k6.portable.$env:VERSION.nupkg?publish=1&override=1"
+
+# publish-macos:
+# runs-on: macos-latest
+# needs: [deps, lint, test, test-cov, configure, build]
+# if: startsWith(github.ref, 'refs/tags/v')
+# env:
+# VERSION: ${{ needs.configure.outputs.version }}
+# steps:
+# - name: Set up Homebrew
+# uses: Homebrew/actions/setup-homebrew@cd7c1eba155dc11d77aa3e3e4013836ad96a6894
+# - name: Create version bump PR
+# run: brew bump-formula-pr k6 --tag="$VERSION" --revision="$GITHUB_SHA"
diff --git a/.golangci.yml b/.golangci.yml
index 6deb24bc8e..1739f39e76 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -60,4 +60,5 @@ linters:
- wsl
- gomnd
- goerr113 # most of the errors here are meant for humans
+ - nlreturn
fast: false
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index b5d1e7ac4a..0000000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,83 +0,0 @@
-image: Visual Studio 2017
-clone_folder: 'c:\gopath\src\github.com\%APPVEYOR_REPO_NAME%'
-
-# Do not build feature branch with open Pull Requests
-skip_branch_with_pr: true
-
-environment:
- # improve readability
- VCS_URL: 'https://github.com/%APPVEYOR_REPO_NAME%'
- # specific to go
- VERSION: "%APPVEYOR_REPO_TAG_NAME:v=%"
- GOPATH: c:\gopath
- GOVERSION: 1.14.9
- GOMAXPROCS: 2
- CGO_ENABLED: '0'
- GOARCH: amd64
- BINTRAY_KEY:
- secure: 0DFVlQR9tBvdTiULPdCw12VBf2Zzy/hpPiPtlKhHdaatIBdwB6i1HhPcgh0kDEBr
- GPG_PASSPHRASE:
- secure: CMQ+U+qVVdhIr1Eip5nGPbaGFggVvSjg/BpSY0EpLbQ=
-
-# prepare system and project
-install:
- - choco install wixtoolset pandoc -y
- - refreshenv
- # ensure wix and go are available in PATH
- - set PATH=C:\go\bin;%GOPATH%\bin;%WIX%\bin;%PATH%
- - ps: |
- Remove-Item 'C:\go' -Recurse -Force -ErrorAction Ignore
- Remove-Item 'C:\go-x86' -Recurse -Force -ErrorAction Ignore
-
- Write-Host "Downloading..."
- $goDistPath = "$env:TEMP\go" + $env:GOVERSION + ".windows-amd64.zip"
- (New-Object Net.WebClient).DownloadFile("https://dl.google.com/go/go" + $env:GOVERSION + ".windows-amd64.zip", $goDistPath)
-
- Write-Host "Unpacking..."
- 7z x $goDistPath -oC:\gotmp-x64 | Out-Null
- [IO.Directory]::Move('C:\gotmp-x64\go', 'C:\go')
- Remove-Item 'C:\gotmp-x64' -Recurse -Force
- del $goDistPath
-
- Write-Host "Testing..."
- - go version
- - echo "NumCores:%NUMBER_OF_PROCESSORS%"
- - systeminfo
-
-
-# build msi artifacts
-build_script:
- # In case of non tag build, mock a version
- - if "%APPVEYOR_REPO_TAG%" == "false" (set VERSION="0.0.1")
- - cd %APPVEYOR_BUILD_FOLDER%
- - pandoc -s -f markdown -t rtf -o packaging\LICENSE.rtf LICENSE.md
- - go version
- - go build -a -trimpath -ldflags "-s -w" -o packaging\k6.exe
- - cd %APPVEYOR_BUILD_FOLDER%\packaging
- - candle.exe -arch x64 -dVERSION=%VERSION% k6.wxs
- - light.exe -ext WixUIExtension k6.wixobj
-
-test_script:
- - cd %APPVEYOR_BUILD_FOLDER%
- - go version
- - go test -p 1 ./...
-
-deploy_script:
- - cd %APPVEYOR_BUILD_FOLDER%\packaging
- # Checking if the build has started by pushed tag
- - ps: |
- if ( $env:APPVEYOR_REPO_TAG -eq "false" ) { Exit-AppveyorBuild }
- # Publishing the msi
- - 'curl --fail -H "X-GPG-PASSPHRASE: %GPG_PASSPHRASE%" -T k6.msi "https://%BINTRAY_USER%:%BINTRAY_KEY%@api.bintray.com/content/loadimpact/windows/k6/%VERSION%/k6-v%VERSION%-amd64.msi?publish=1&override=1"'
- - ps: |
- # Create Chocolately Package
- mkdir .\k6.portable
-
- Copy-Item -Path .\k6.portable.nuspec -Destination .\k6.portable\k6.portable.nuspec
- Copy-Item -Path .\k6.exe -Destination .\k6.portable\k6.exe
-
- Set-Location -Path .\k6.portable\
- (Get-Content '.\k6.portable.nuspec' -Raw).Replace("__REPLACE__", "$($env:APPVEYOR_REPO_TAG_NAME.substring(1))") | Out-File '.\k6.portable.nuspec'
- choco pack
- # Publising the chocolatey package
- - 'curl --fail -H "X-GPG-PASSPHRASE: %GPG_PASSPHRASE%" -T .\k6.portable.%VERSION%.nupkg "https://%BINTRAY_USER%:%BINTRAY_KEY%@api.bintray.com/content/loadimpact/choco/k6.portable/%VERSION%/k6.portable.%VERSION%.nupkg?publish=1&override=1"'
diff --git a/build-release.sh b/build-release.sh
index 57f76a7034..3a58008150 100755
--- a/build-release.sh
+++ b/build-release.sh
@@ -1,87 +1,101 @@
-#!/usr/bin/env bash
+#!/bin/bash
set -eEuo pipefail
eval "$(go env)"
-# To override the latest git tag as the version, pass something else as the first arg.
-VERSION=${1:-$(git describe --tags --always --dirty)}
+OUT_DIR="${1-dist}"
+# To override the latest git tag as the version, pass something else as the second arg.
+VERSION=${2:-$(git describe --tags --always --dirty)}
-# To overwrite the version details, pass something as the second arg. Empty string disables it.
-VERSION_DETAILS=${2-"$(date -u +"%FT%T%z")/$(git describe --always --long --dirty)"}
+# To overwrite the version details, pass something as the third arg. Empty string disables it.
+VERSION_DETAILS=${3-"$(date -u +"%FT%T%z")/$(git describe --always --long --dirty)"}
-make_archive() {
- local FMT="$1" DIR="$2"
+build() {
+ local ALIAS="$1" SUFFIX="${2}" # Any other arguments are passed to the go build command as env vars
+ local NAME="k6-${VERSION}-${ALIAS}"
- case $FMT in
- zip)
- zip -rq9 "$DIR.zip" "$DIR"
- ;;
- tgz)
- tar -zcf "$DIR.tar.gz" "$DIR"
- ;;
- esac
-}
-
-build_dist() {
- local ALIAS="$1" FMT="${2}" SUFFIX="${3}" # Any other arguments are passed to the go build command as env vars
- local DIR="k6-${VERSION}-${ALIAS}"
-
- local BUILD_ENV=("${@:4}")
- local BUILD_ARGS=(-o "dist/$DIR/k6${SUFFIX}" -trimpath)
-
- if [ -n "$VERSION_DETAILS" ]; then
- BUILD_ARGS+=(-ldflags "-X github.com/loadimpact/k6/lib/consts.VersionDetails=$VERSION_DETAILS")
- fi
-
- echo "- Building platform: ${ALIAS} (" "${BUILD_ENV[@]}" "go build" "${BUILD_ARGS[@]}" ")"
+ local BUILD_ENV=("${@:3}")
+ local BUILD_ARGS=(-o "${OUT_DIR}/${NAME}/k6${SUFFIX}" -trimpath)
- # Clean out any old remnants of failed builds.
- rm -rf "dist/$DIR"
- mkdir -p "dist/$DIR"
+ if [ -n "$VERSION_DETAILS" ]; then
+ BUILD_ARGS+=(-ldflags "-X github.com/loadimpact/k6/lib/consts.VersionDetails=$VERSION_DETAILS")
+ fi
- # Subshell to not mess with the current env vars or CWD
- (
- export "${BUILD_ENV[@]}"
+ echo "- Building platform: ${ALIAS} (" "${BUILD_ENV[@]}" "go build" "${BUILD_ARGS[@]}" ")"
- # Build a binary
- go build "${BUILD_ARGS[@]}"
+ mkdir -p "${OUT_DIR}/${NAME}"
- # Archive it all, native format depends on the platform.
- cd dist
- make_archive "$FMT" "$DIR"
- )
+ # Subshell to not mess with the current env vars or CWD
+ (
+ export "${BUILD_ENV[@]}"
+ # Build a binary
+ go build "${BUILD_ARGS[@]}"
+ )
+}
- # Delete the source files.
- rm -rf "dist/$DIR"
+package() {
+ local ALIAS="$1" FMT="$2"
+ local NAME="k6-${VERSION}-${ALIAS}"
+ echo "- Creating ${NAME}.${FMT} package..."
+ case $FMT in
+ deb|rpm)
+ # The go-bin-* tools expect the binary in /tmp/
+ [ ! -r /tmp/k6 ] && cp "${OUT_DIR}/${NAME}/k6" /tmp/k6
+ "go-bin-${FMT}" generate --file "packaging/${FMT}.json" -a amd64 \
+ --version "${VERSION#v}" -o "${OUT_DIR}/k6-${VERSION}-amd64.${FMT}"
+ ;;
+ tgz)
+ tar -C "${OUT_DIR}" -zcf "${OUT_DIR}/${NAME}.tar.gz" "$NAME"
+ ;;
+ zip)
+ (cd "${OUT_DIR}" && zip -rq9 - "$NAME") > "${OUT_DIR}/${NAME}.zip"
+ ;;
+ *)
+ echo "Unknown format: $FMT"
+ return 1
+ ;;
+ esac
}
+CHECKSUM_FILE="k6-${VERSION}-checksums.txt"
checksum() {
- local CHECKSUM_FILE="k6-${VERSION}-checksums.txt"
-
- if command -v sha256sum > /dev/null; then
- CHECKSUM_CMD=("sha256sum")
- elif command -v shasum > /dev/null; then
- CHECKSUM_CMD=("shasum" "-a" "256")
- else
- echo "ERROR: unable to find a command to compute sha-256 hash"
- return 1
- fi
-
- rm -f "dist/$CHECKSUM_FILE"
- ( cd dist && for x in *; do [ -f "$x" ] && "${CHECKSUM_CMD[@]}" -- "$x" >> "$CHECKSUM_FILE"; done )
+ if command -v sha256sum > /dev/null; then
+ CHECKSUM_CMD=("sha256sum")
+ elif command -v shasum > /dev/null; then
+ CHECKSUM_CMD=("shasum" "-a" "256")
+ else
+ echo "ERROR: unable to find a command to compute sha-256 hash"
+ exit 1
+ fi
+
+ echo "--- Generating checksum file..."
+ rm -f "${OUT_DIR}/$CHECKSUM_FILE"
+ (cd "$OUT_DIR" && find . -maxdepth 1 -type f -printf '%P\n' | sort | xargs "${CHECKSUM_CMD[@]}" > "$CHECKSUM_FILE")
+}
+
+cleanup() {
+ find "$OUT_DIR" -mindepth 1 -maxdepth 1 -type d -exec rm -rf {} \;
+ echo "--- Cleaned ${OUT_DIR}"
}
+trap cleanup EXIT
echo "--- Building Release: ${VERSION}"
-echo "-> Building platform packages..."
-mkdir -p dist
+mkdir -p "$OUT_DIR"
+
+build mac "" GOOS=darwin GOARCH=amd64
+build win32 .exe GOOS=windows GOARCH=386
+build win64 .exe GOOS=windows GOARCH=amd64
+build linux32 "" GOOS=linux GOARCH=386 CGO_ENABLED=0
+build linux64 "" GOOS=linux GOARCH=amd64 CGO_ENABLED=0
-build_dist mac zip "" GOOS=darwin GOARCH=amd64
-build_dist win32 zip .exe GOOS=windows GOARCH=386
-build_dist win64 zip .exe GOOS=windows GOARCH=amd64
-build_dist linux32 tgz "" GOOS=linux GOARCH=386 CGO_ENABLED=0
-build_dist linux64 tgz "" GOOS=linux GOARCH=amd64 CGO_ENABLED=0
+package linux32 tgz
+package linux64 tgz
+package linux64 rpm
+package linux64 deb
+package mac zip
+package win32 zip
+package win64 zip
-echo "-> Generating checksum file..."
checksum
diff --git a/cmd/testdata/example.js b/cmd/testdata/example.js
index 96470d6894..f5d8fe5911 100644
--- a/cmd/testdata/example.js
+++ b/cmd/testdata/example.js
@@ -15,34 +15,34 @@ export default function() {
// Request #0
res = http.post("https://some-host.example.com/checkout/v3/orders",
`{
- "locale": "sv-SE",
+ "locale": "sv-SE",
"merchant_urls": {
- "checkout": "https://some-fourth-host.example.com/v1/redirect/checkout",
- "confirmation": "https://some-fourth-host.example.com/v1/redirect/confirm",
- "push": "https://some-fourth-host.example.com/v1/callback/push/{checkout.order.id}?merchant_id=smi-merchant-all-validation\u0026env=perf",
+ "checkout": "https://some-fourth-host.example.com/v1/redirect/checkout",
+ "confirmation": "https://some-fourth-host.example.com/v1/redirect/confirm",
+ "push": "https://some-fourth-host.example.com/v1/callback/push/{checkout.order.id}?merchant_id=smi-merchant-all-validation\u0026env=perf",
"terms": "https://some-fourth-host.example.com/v1/redirect/terms"
- },
- "options": {},
- "order_amount": 16278,
+ },
+ "options": {},
+ "order_amount": 16278,
"order_lines": [
{
- "image_url": "https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg",
- "name": "Mediokra Betong Lampa. Tangentbord",
- "product_url": "http://aufderharluettgen.info/haven",
- "quantity": 1,
- "quantity_unit": "kg",
- "reference": "jkwedq9f6t",
- "tax_rate": 800,
- "total_amount": 16278,
- "total_discount_amount": 0,
- "total_tax_amount": 1206,
- "type": "physical",
+ "image_url": "https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg",
+ "name": "Mediokra Betong Lampa. Tangentbord",
+ "product_url": "http://aufderharluettgen.info/haven",
+ "quantity": 1,
+ "quantity_unit": "kg",
+ "reference": "jkwedq9f6t",
+ "tax_rate": 800,
+ "total_amount": 16278,
+ "total_discount_amount": 0,
+ "total_tax_amount": 1206,
+ "type": "physical",
"unit_price": 16278
}
- ],
- "order_tax_amount": 1206,
- "purchase_country": "se",
- "purchase_currency": "SEK",
+ ],
+ "order_tax_amount": 1206,
+ "purchase_country": "se",
+ "purchase_currency": "SEK",
"shipping_countries": ["AD", "AE", "AG", "AI", "AL", "AM", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BB", "BD", "BE", "BF", "BG", "BH", "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BZ", "CA", "CC", "CH", "CK", "CL", "CM", "CO", "CR", "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EH", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GP", "GQ", "GR", "GS", "GT", "GU", "HK", "HM", "HN", "HR", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KY", "KZ", "LC", "LI", "LK", "LS", "LT", "LU", "LV", "MA", "MC", "ME", "MF", "MG", "MH", "MK", "ML", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RW", "SA", "SB", "SC", "SE", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SX", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TO", "TR", "TT", "TV", "TW", "TZ", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "WF", "WS", "YT", "ZA", "ZM"]
}`,
{
@@ -92,81 +92,81 @@ export default function() {
// Request #3
res = http.post("https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25",
`{
- "allowed_billing_countries": ["${json.allowed_billing_countries[0]}", "${json.allowed_billing_countries[1]}", "${json.allowed_billing_countries[2]}", "${json.allowed_billing_countries[3]}", "${json.allowed_billing_countries[4]}", "${json.allowed_billing_countries[5]}", "${json.allowed_billing_countries[6]}", "${json.allowed_billing_countries[7]}", "${json.allowed_billing_countries[8]}", "${json.allowed_billing_countries[9]}", "${json.allowed_billing_countries[10]}", "${json.allowed_billing_countries[11]}", "${json.allowed_billing_countries[12]}", "${json.allowed_billing_countries[13]}", "${json.allowed_billing_countries[14]}", "${json.allowed_billing_countries[15]}", "${json.allowed_billing_countries[16]}", "${json.allowed_billing_countries[17]}", "${json.allowed_billing_countries[18]}", "${json.allowed_billing_countries[19]}", "${json.allowed_billing_countries[20]}", "${json.allowed_billing_countries[21]}", "${json.allowed_billing_countries[22]}", "${json.allowed_billing_countries[23]}", "${json.allowed_billing_countries[24]}", "${json.allowed_billing_countries[25]}", "${json.allowed_billing_countries[26]}", "${json.allowed_billing_countries[27]}", "${json.allowed_billing_countries[28]}", "${json.allowed_billing_countries[29]}", "${json.allowed_billing_countries[30]}", "${json.allowed_billing_countries[31]}", "${json.allowed_billing_countries[32]}", "${json.allowed_billing_countries[33]}", "${json.allowed_billing_countries[34]}", "${json.allowed_billing_countries[35]}", "${json.allowed_billing_countries[36]}", "${json.allowed_billing_countries[37]}", "${json.allowed_billing_countries[38]}", "${json.allowed_billing_countries[39]}", "${json.allowed_billing_countries[40]}", "${json.allowed_billing_countries[41]}", "${json.allowed_billing_countries[42]}", "${json.allowed_billing_countries[43]}", "${json.allowed_billing_countries[44]}", "${json.allowed_billing_countries[45]}", "${json.allowed_billing_countries[46]}", "${json.allowed_billing_countries[47]}", "${json.allowed_billing_countries[48]}", "${json.allowed_billing_countries[49]}", "${json.allowed_billing_countries[50]}", "${json.allowed_billing_countries[51]}", "${json.allowed_billing_countries[52]}", "${json.allowed_billing_countries[53]}", "${json.allowed_billing_countries[54]}", "${json.allowed_billing_countries[55]}", "${json.allowed_billing_countries[56]}", "${json.allowed_billing_countries[57]}", "${json.allowed_billing_countries[58]}", "${json.allowed_billing_countries[59]}", "${json.allowed_billing_countries[60]}", "${json.allowed_billing_countries[61]}", "${json.allowed_billing_countries[62]}", "${json.allowed_billing_countries[63]}", "${json.allowed_billing_countries[64]}", "${json.allowed_billing_countries[65]}", "${json.allowed_billing_countries[66]}", "${json.allowed_billing_countries[67]}", "${json.allowed_billing_countries[68]}", "${json.allowed_billing_countries[69]}", "${json.allowed_billing_countries[70]}", "${json.allowed_billing_countries[71]}", "${json.allowed_billing_countries[72]}", "${json.allowed_billing_countries[73]}", "${json.allowed_billing_countries[74]}", "${json.allowed_billing_countries[75]}", "${json.allowed_billing_countries[76]}", "${json.allowed_billing_countries[77]}", "${json.allowed_billing_countries[78]}", "${json.allowed_billing_countries[79]}", "${json.allowed_billing_countries[80]}", "${json.allowed_billing_countries[81]}", "${json.allowed_billing_countries[82]}", "${json.allowed_billing_countries[83]}", "${json.allowed_billing_countries[84]}", "${json.allowed_billing_countries[85]}", "${json.allowed_billing_countries[86]}", "${json.allowed_billing_countries[87]}", "${json.allowed_billing_countries[88]}", "${json.allowed_billing_countries[89]}", "${json.allowed_billing_countries[90]}", "${json.allowed_billing_countries[91]}", "${json.allowed_billing_countries[92]}", "${json.allowed_billing_countries[93]}", "${json.allowed_billing_countries[94]}", "${json.allowed_billing_countries[95]}", "${json.allowed_billing_countries[96]}", "${json.allowed_billing_countries[97]}", "${json.allowed_billing_countries[98]}", "${json.allowed_billing_countries[99]}", "${json.allowed_billing_countries[100]}", "${json.allowed_billing_countries[101]}", "${json.allowed_billing_countries[102]}", "${json.allowed_billing_countries[103]}", "${json.allowed_billing_countries[104]}", "${json.allowed_billing_countries[105]}", "${json.allowed_billing_countries[106]}", "${json.allowed_billing_countries[107]}", "${json.allowed_billing_countries[108]}", "${json.allowed_billing_countries[109]}", "${json.allowed_billing_countries[110]}", "${json.allowed_billing_countries[111]}", "${json.allowed_billing_countries[112]}", "${json.allowed_billing_countries[113]}", "${json.allowed_billing_countries[114]}", "${json.allowed_billing_countries[115]}", "${json.allowed_billing_countries[116]}", "${json.allowed_billing_countries[117]}", "${json.allowed_billing_countries[118]}", "${json.allowed_billing_countries[119]}", "${json.allowed_billing_countries[120]}", "${json.allowed_billing_countries[121]}", "${json.allowed_billing_countries[122]}", "${json.allowed_billing_countries[123]}", "${json.allowed_billing_countries[124]}", "${json.allowed_billing_countries[125]}", "${json.allowed_billing_countries[126]}", "${json.allowed_billing_countries[127]}", "${json.allowed_billing_countries[128]}", "${json.allowed_billing_countries[129]}", "${json.allowed_billing_countries[130]}", "${json.allowed_billing_countries[131]}", "${json.allowed_billing_countries[132]}", "${json.allowed_billing_countries[133]}", "${json.allowed_billing_countries[134]}", "${json.allowed_billing_countries[135]}", "${json.allowed_billing_countries[136]}", "${json.allowed_billing_countries[137]}", "${json.allowed_billing_countries[138]}", "${json.allowed_billing_countries[139]}", "${json.allowed_billing_countries[140]}", "${json.allowed_billing_countries[141]}", "${json.allowed_billing_countries[142]}", "${json.allowed_billing_countries[143]}", "${json.allowed_billing_countries[144]}", "${json.allowed_billing_countries[145]}", "${json.allowed_billing_countries[146]}", "${json.allowed_billing_countries[147]}", "${json.allowed_billing_countries[148]}", "${json.allowed_billing_countries[149]}", "${json.allowed_billing_countries[150]}", "${json.allowed_billing_countries[151]}", "${json.allowed_billing_countries[152]}", "${json.allowed_billing_countries[153]}", "${json.allowed_billing_countries[154]}", "${json.allowed_billing_countries[155]}", "${json.allowed_billing_countries[156]}", "${json.allowed_billing_countries[157]}", "${json.allowed_billing_countries[158]}", "${json.allowed_billing_countries[159]}", "${json.allowed_billing_countries[160]}", "${json.allowed_billing_countries[161]}", "${json.allowed_billing_countries[162]}", "${json.allowed_billing_countries[163]}", "${json.allowed_billing_countries[164]}", "${json.allowed_billing_countries[165]}", "${json.allowed_billing_countries[166]}", "${json.allowed_billing_countries[167]}", "${json.allowed_billing_countries[168]}", "${json.allowed_billing_countries[169]}", "${json.allowed_billing_countries[170]}", "${json.allowed_billing_countries[171]}", "${json.allowed_billing_countries[172]}", "${json.allowed_billing_countries[173]}", "${json.allowed_billing_countries[174]}", "${json.allowed_billing_countries[175]}", "${json.allowed_billing_countries[176]}", "${json.allowed_billing_countries[177]}", "${json.allowed_billing_countries[178]}", "${json.allowed_billing_countries[179]}", "${json.allowed_billing_countries[180]}", "${json.allowed_billing_countries[181]}", "${json.allowed_billing_countries[182]}", "${json.allowed_billing_countries[183]}", "${json.allowed_billing_countries[184]}", "${json.allowed_billing_countries[185]}", "${json.allowed_billing_countries[186]}", "${json.allowed_billing_countries[187]}", "${json.allowed_billing_countries[188]}", "${json.allowed_billing_countries[189]}", "${json.allowed_billing_countries[190]}", "${json.allowed_billing_countries[191]}", "${json.allowed_billing_countries[192]}", "${json.allowed_billing_countries[193]}", "${json.allowed_billing_countries[194]}", "${json.allowed_billing_countries[195]}", "${json.allowed_billing_countries[196]}", "${json.allowed_billing_countries[197]}", "${json.allowed_billing_countries[198]}", "${json.allowed_billing_countries[199]}", "${json.allowed_billing_countries[200]}", "${json.allowed_billing_countries[201]}", "${json.allowed_billing_countries[202]}", "${json.allowed_billing_countries[203]}", "${json.allowed_billing_countries[204]}", "${json.allowed_billing_countries[205]}", "${json.allowed_billing_countries[206]}", "${json.allowed_billing_countries[207]}", "${json.allowed_billing_countries[208]}", "${json.allowed_billing_countries[209]}", "${json.allowed_billing_countries[210]}"],
- "allowed_shipping_countries": ["${json.allowed_shipping_countries[0]}", "${json.allowed_shipping_countries[1]}", "${json.allowed_shipping_countries[2]}", "${json.allowed_shipping_countries[3]}", "${json.allowed_shipping_countries[4]}", "${json.allowed_shipping_countries[5]}", "${json.allowed_shipping_countries[6]}", "${json.allowed_shipping_countries[7]}", "${json.allowed_shipping_countries[8]}", "${json.allowed_shipping_countries[9]}", "${json.allowed_shipping_countries[10]}", "${json.allowed_shipping_countries[11]}", "${json.allowed_shipping_countries[12]}", "${json.allowed_shipping_countries[13]}", "${json.allowed_shipping_countries[14]}", "${json.allowed_shipping_countries[15]}", "${json.allowed_shipping_countries[16]}", "${json.allowed_shipping_countries[17]}", "${json.allowed_shipping_countries[18]}", "${json.allowed_shipping_countries[19]}", "${json.allowed_shipping_countries[20]}", "${json.allowed_shipping_countries[21]}", "${json.allowed_shipping_countries[22]}", "${json.allowed_shipping_countries[23]}", "${json.allowed_shipping_countries[24]}", "${json.allowed_shipping_countries[25]}", "${json.allowed_shipping_countries[26]}", "${json.allowed_shipping_countries[27]}", "${json.allowed_shipping_countries[28]}", "${json.allowed_shipping_countries[29]}", "${json.allowed_shipping_countries[30]}", "${json.allowed_shipping_countries[31]}", "${json.allowed_shipping_countries[32]}", "${json.allowed_shipping_countries[33]}", "${json.allowed_shipping_countries[34]}", "${json.allowed_shipping_countries[35]}", "${json.allowed_shipping_countries[36]}", "${json.allowed_shipping_countries[37]}", "${json.allowed_shipping_countries[38]}", "${json.allowed_shipping_countries[39]}", "${json.allowed_shipping_countries[40]}", "${json.allowed_shipping_countries[41]}", "${json.allowed_shipping_countries[42]}", "${json.allowed_shipping_countries[43]}", "${json.allowed_shipping_countries[44]}", "${json.allowed_shipping_countries[45]}", "${json.allowed_shipping_countries[46]}", "${json.allowed_shipping_countries[47]}", "${json.allowed_shipping_countries[48]}", "${json.allowed_shipping_countries[49]}", "${json.allowed_shipping_countries[50]}", "${json.allowed_shipping_countries[51]}", "${json.allowed_shipping_countries[52]}", "${json.allowed_shipping_countries[53]}", "${json.allowed_shipping_countries[54]}", "${json.allowed_shipping_countries[55]}", "${json.allowed_shipping_countries[56]}", "${json.allowed_shipping_countries[57]}", "${json.allowed_shipping_countries[58]}", "${json.allowed_shipping_countries[59]}", "${json.allowed_shipping_countries[60]}", "${json.allowed_shipping_countries[61]}", "${json.allowed_shipping_countries[62]}", "${json.allowed_shipping_countries[63]}", "${json.allowed_shipping_countries[64]}", "${json.allowed_shipping_countries[65]}", "${json.allowed_shipping_countries[66]}", "${json.allowed_shipping_countries[67]}", "${json.allowed_shipping_countries[68]}", "${json.allowed_shipping_countries[69]}", "${json.allowed_shipping_countries[70]}", "${json.allowed_shipping_countries[71]}", "${json.allowed_shipping_countries[72]}", "${json.allowed_shipping_countries[73]}", "${json.allowed_shipping_countries[74]}", "${json.allowed_shipping_countries[75]}", "${json.allowed_shipping_countries[76]}", "${json.allowed_shipping_countries[77]}", "${json.allowed_shipping_countries[78]}", "${json.allowed_shipping_countries[79]}", "${json.allowed_shipping_countries[80]}", "${json.allowed_shipping_countries[81]}", "${json.allowed_shipping_countries[82]}", "${json.allowed_shipping_countries[83]}", "${json.allowed_shipping_countries[84]}", "${json.allowed_shipping_countries[85]}", "${json.allowed_shipping_countries[86]}", "${json.allowed_shipping_countries[87]}", "${json.allowed_shipping_countries[88]}", "${json.allowed_shipping_countries[89]}", "${json.allowed_shipping_countries[90]}", "${json.allowed_shipping_countries[91]}", "${json.allowed_shipping_countries[92]}", "${json.allowed_shipping_countries[93]}", "${json.allowed_shipping_countries[94]}", "${json.allowed_shipping_countries[95]}", "${json.allowed_shipping_countries[96]}", "${json.allowed_shipping_countries[97]}", "${json.allowed_shipping_countries[98]}", "${json.allowed_shipping_countries[99]}", "${json.allowed_shipping_countries[100]}", "${json.allowed_shipping_countries[101]}", "${json.allowed_shipping_countries[102]}", "${json.allowed_shipping_countries[103]}", "${json.allowed_shipping_countries[104]}", "${json.allowed_shipping_countries[105]}", "${json.allowed_shipping_countries[106]}", "${json.allowed_shipping_countries[107]}", "${json.allowed_shipping_countries[108]}", "${json.allowed_shipping_countries[109]}", "${json.allowed_shipping_countries[110]}", "${json.allowed_shipping_countries[111]}", "${json.allowed_shipping_countries[112]}", "${json.allowed_shipping_countries[113]}", "${json.allowed_shipping_countries[114]}", "${json.allowed_shipping_countries[115]}", "${json.allowed_shipping_countries[116]}", "${json.allowed_shipping_countries[117]}", "${json.allowed_shipping_countries[118]}", "${json.allowed_shipping_countries[119]}", "${json.allowed_shipping_countries[120]}", "${json.allowed_shipping_countries[121]}", "${json.allowed_shipping_countries[122]}", "${json.allowed_shipping_countries[123]}", "${json.allowed_shipping_countries[124]}", "${json.allowed_shipping_countries[125]}", "${json.allowed_shipping_countries[126]}", "${json.allowed_shipping_countries[127]}", "${json.allowed_shipping_countries[128]}", "${json.allowed_shipping_countries[129]}", "${json.allowed_shipping_countries[130]}", "${json.allowed_shipping_countries[131]}", "${json.allowed_shipping_countries[132]}", "${json.allowed_shipping_countries[133]}", "${json.allowed_shipping_countries[134]}", "${json.allowed_shipping_countries[135]}", "${json.allowed_shipping_countries[136]}", "${json.allowed_shipping_countries[137]}", "${json.allowed_shipping_countries[138]}", "${json.allowed_shipping_countries[139]}", "${json.allowed_shipping_countries[140]}", "${json.allowed_shipping_countries[141]}", "${json.allowed_shipping_countries[142]}", "${json.allowed_shipping_countries[143]}", "${json.allowed_shipping_countries[144]}", "${json.allowed_shipping_countries[145]}", "${json.allowed_shipping_countries[146]}", "${json.allowed_shipping_countries[147]}", "${json.allowed_shipping_countries[148]}", "${json.allowed_shipping_countries[149]}", "${json.allowed_shipping_countries[150]}", "${json.allowed_shipping_countries[151]}", "${json.allowed_shipping_countries[152]}", "${json.allowed_shipping_countries[153]}", "${json.allowed_shipping_countries[154]}", "${json.allowed_shipping_countries[155]}", "${json.allowed_shipping_countries[156]}", "${json.allowed_shipping_countries[157]}", "${json.allowed_shipping_countries[158]}", "${json.allowed_shipping_countries[159]}", "${json.allowed_shipping_countries[160]}", "${json.allowed_shipping_countries[161]}", "${json.allowed_shipping_countries[162]}", "${json.allowed_shipping_countries[163]}", "${json.allowed_shipping_countries[164]}", "${json.allowed_shipping_countries[165]}", "${json.allowed_shipping_countries[166]}", "${json.allowed_shipping_countries[167]}", "${json.allowed_shipping_countries[168]}", "${json.allowed_shipping_countries[169]}", "${json.allowed_shipping_countries[170]}", "${json.allowed_shipping_countries[171]}", "${json.allowed_shipping_countries[172]}", "${json.allowed_shipping_countries[173]}", "${json.allowed_shipping_countries[174]}", "${json.allowed_shipping_countries[175]}", "${json.allowed_shipping_countries[176]}", "${json.allowed_shipping_countries[177]}", "${json.allowed_shipping_countries[178]}", "${json.allowed_shipping_countries[179]}", "${json.allowed_shipping_countries[180]}", "${json.allowed_shipping_countries[181]}", "${json.allowed_shipping_countries[182]}", "${json.allowed_shipping_countries[183]}", "${json.allowed_shipping_countries[184]}", "${json.allowed_shipping_countries[185]}", "${json.allowed_shipping_countries[186]}", "${json.allowed_shipping_countries[187]}", "${json.allowed_shipping_countries[188]}", "${json.allowed_shipping_countries[189]}", "${json.allowed_shipping_countries[190]}", "${json.allowed_shipping_countries[191]}", "${json.allowed_shipping_countries[192]}", "${json.allowed_shipping_countries[193]}", "${json.allowed_shipping_countries[194]}", "${json.allowed_shipping_countries[195]}", "${json.allowed_shipping_countries[196]}", "${json.allowed_shipping_countries[197]}", "${json.allowed_shipping_countries[198]}", "${json.allowed_shipping_countries[199]}", "${json.allowed_shipping_countries[200]}", "${json.allowed_shipping_countries[201]}", "${json.allowed_shipping_countries[202]}", "${json.allowed_shipping_countries[203]}", "${json.allowed_shipping_countries[204]}", "${json.allowed_shipping_countries[205]}", "${json.allowed_shipping_countries[206]}", "${json.allowed_shipping_countries[207]}", "${json.allowed_shipping_countries[208]}", "${json.allowed_shipping_countries[209]}", "${json.allowed_shipping_countries[210]}"],
+ "allowed_billing_countries": ["${json.allowed_billing_countries[0]}", "${json.allowed_billing_countries[1]}", "${json.allowed_billing_countries[2]}", "${json.allowed_billing_countries[3]}", "${json.allowed_billing_countries[4]}", "${json.allowed_billing_countries[5]}", "${json.allowed_billing_countries[6]}", "${json.allowed_billing_countries[7]}", "${json.allowed_billing_countries[8]}", "${json.allowed_billing_countries[9]}", "${json.allowed_billing_countries[10]}", "${json.allowed_billing_countries[11]}", "${json.allowed_billing_countries[12]}", "${json.allowed_billing_countries[13]}", "${json.allowed_billing_countries[14]}", "${json.allowed_billing_countries[15]}", "${json.allowed_billing_countries[16]}", "${json.allowed_billing_countries[17]}", "${json.allowed_billing_countries[18]}", "${json.allowed_billing_countries[19]}", "${json.allowed_billing_countries[20]}", "${json.allowed_billing_countries[21]}", "${json.allowed_billing_countries[22]}", "${json.allowed_billing_countries[23]}", "${json.allowed_billing_countries[24]}", "${json.allowed_billing_countries[25]}", "${json.allowed_billing_countries[26]}", "${json.allowed_billing_countries[27]}", "${json.allowed_billing_countries[28]}", "${json.allowed_billing_countries[29]}", "${json.allowed_billing_countries[30]}", "${json.allowed_billing_countries[31]}", "${json.allowed_billing_countries[32]}", "${json.allowed_billing_countries[33]}", "${json.allowed_billing_countries[34]}", "${json.allowed_billing_countries[35]}", "${json.allowed_billing_countries[36]}", "${json.allowed_billing_countries[37]}", "${json.allowed_billing_countries[38]}", "${json.allowed_billing_countries[39]}", "${json.allowed_billing_countries[40]}", "${json.allowed_billing_countries[41]}", "${json.allowed_billing_countries[42]}", "${json.allowed_billing_countries[43]}", "${json.allowed_billing_countries[44]}", "${json.allowed_billing_countries[45]}", "${json.allowed_billing_countries[46]}", "${json.allowed_billing_countries[47]}", "${json.allowed_billing_countries[48]}", "${json.allowed_billing_countries[49]}", "${json.allowed_billing_countries[50]}", "${json.allowed_billing_countries[51]}", "${json.allowed_billing_countries[52]}", "${json.allowed_billing_countries[53]}", "${json.allowed_billing_countries[54]}", "${json.allowed_billing_countries[55]}", "${json.allowed_billing_countries[56]}", "${json.allowed_billing_countries[57]}", "${json.allowed_billing_countries[58]}", "${json.allowed_billing_countries[59]}", "${json.allowed_billing_countries[60]}", "${json.allowed_billing_countries[61]}", "${json.allowed_billing_countries[62]}", "${json.allowed_billing_countries[63]}", "${json.allowed_billing_countries[64]}", "${json.allowed_billing_countries[65]}", "${json.allowed_billing_countries[66]}", "${json.allowed_billing_countries[67]}", "${json.allowed_billing_countries[68]}", "${json.allowed_billing_countries[69]}", "${json.allowed_billing_countries[70]}", "${json.allowed_billing_countries[71]}", "${json.allowed_billing_countries[72]}", "${json.allowed_billing_countries[73]}", "${json.allowed_billing_countries[74]}", "${json.allowed_billing_countries[75]}", "${json.allowed_billing_countries[76]}", "${json.allowed_billing_countries[77]}", "${json.allowed_billing_countries[78]}", "${json.allowed_billing_countries[79]}", "${json.allowed_billing_countries[80]}", "${json.allowed_billing_countries[81]}", "${json.allowed_billing_countries[82]}", "${json.allowed_billing_countries[83]}", "${json.allowed_billing_countries[84]}", "${json.allowed_billing_countries[85]}", "${json.allowed_billing_countries[86]}", "${json.allowed_billing_countries[87]}", "${json.allowed_billing_countries[88]}", "${json.allowed_billing_countries[89]}", "${json.allowed_billing_countries[90]}", "${json.allowed_billing_countries[91]}", "${json.allowed_billing_countries[92]}", "${json.allowed_billing_countries[93]}", "${json.allowed_billing_countries[94]}", "${json.allowed_billing_countries[95]}", "${json.allowed_billing_countries[96]}", "${json.allowed_billing_countries[97]}", "${json.allowed_billing_countries[98]}", "${json.allowed_billing_countries[99]}", "${json.allowed_billing_countries[100]}", "${json.allowed_billing_countries[101]}", "${json.allowed_billing_countries[102]}", "${json.allowed_billing_countries[103]}", "${json.allowed_billing_countries[104]}", "${json.allowed_billing_countries[105]}", "${json.allowed_billing_countries[106]}", "${json.allowed_billing_countries[107]}", "${json.allowed_billing_countries[108]}", "${json.allowed_billing_countries[109]}", "${json.allowed_billing_countries[110]}", "${json.allowed_billing_countries[111]}", "${json.allowed_billing_countries[112]}", "${json.allowed_billing_countries[113]}", "${json.allowed_billing_countries[114]}", "${json.allowed_billing_countries[115]}", "${json.allowed_billing_countries[116]}", "${json.allowed_billing_countries[117]}", "${json.allowed_billing_countries[118]}", "${json.allowed_billing_countries[119]}", "${json.allowed_billing_countries[120]}", "${json.allowed_billing_countries[121]}", "${json.allowed_billing_countries[122]}", "${json.allowed_billing_countries[123]}", "${json.allowed_billing_countries[124]}", "${json.allowed_billing_countries[125]}", "${json.allowed_billing_countries[126]}", "${json.allowed_billing_countries[127]}", "${json.allowed_billing_countries[128]}", "${json.allowed_billing_countries[129]}", "${json.allowed_billing_countries[130]}", "${json.allowed_billing_countries[131]}", "${json.allowed_billing_countries[132]}", "${json.allowed_billing_countries[133]}", "${json.allowed_billing_countries[134]}", "${json.allowed_billing_countries[135]}", "${json.allowed_billing_countries[136]}", "${json.allowed_billing_countries[137]}", "${json.allowed_billing_countries[138]}", "${json.allowed_billing_countries[139]}", "${json.allowed_billing_countries[140]}", "${json.allowed_billing_countries[141]}", "${json.allowed_billing_countries[142]}", "${json.allowed_billing_countries[143]}", "${json.allowed_billing_countries[144]}", "${json.allowed_billing_countries[145]}", "${json.allowed_billing_countries[146]}", "${json.allowed_billing_countries[147]}", "${json.allowed_billing_countries[148]}", "${json.allowed_billing_countries[149]}", "${json.allowed_billing_countries[150]}", "${json.allowed_billing_countries[151]}", "${json.allowed_billing_countries[152]}", "${json.allowed_billing_countries[153]}", "${json.allowed_billing_countries[154]}", "${json.allowed_billing_countries[155]}", "${json.allowed_billing_countries[156]}", "${json.allowed_billing_countries[157]}", "${json.allowed_billing_countries[158]}", "${json.allowed_billing_countries[159]}", "${json.allowed_billing_countries[160]}", "${json.allowed_billing_countries[161]}", "${json.allowed_billing_countries[162]}", "${json.allowed_billing_countries[163]}", "${json.allowed_billing_countries[164]}", "${json.allowed_billing_countries[165]}", "${json.allowed_billing_countries[166]}", "${json.allowed_billing_countries[167]}", "${json.allowed_billing_countries[168]}", "${json.allowed_billing_countries[169]}", "${json.allowed_billing_countries[170]}", "${json.allowed_billing_countries[171]}", "${json.allowed_billing_countries[172]}", "${json.allowed_billing_countries[173]}", "${json.allowed_billing_countries[174]}", "${json.allowed_billing_countries[175]}", "${json.allowed_billing_countries[176]}", "${json.allowed_billing_countries[177]}", "${json.allowed_billing_countries[178]}", "${json.allowed_billing_countries[179]}", "${json.allowed_billing_countries[180]}", "${json.allowed_billing_countries[181]}", "${json.allowed_billing_countries[182]}", "${json.allowed_billing_countries[183]}", "${json.allowed_billing_countries[184]}", "${json.allowed_billing_countries[185]}", "${json.allowed_billing_countries[186]}", "${json.allowed_billing_countries[187]}", "${json.allowed_billing_countries[188]}", "${json.allowed_billing_countries[189]}", "${json.allowed_billing_countries[190]}", "${json.allowed_billing_countries[191]}", "${json.allowed_billing_countries[192]}", "${json.allowed_billing_countries[193]}", "${json.allowed_billing_countries[194]}", "${json.allowed_billing_countries[195]}", "${json.allowed_billing_countries[196]}", "${json.allowed_billing_countries[197]}", "${json.allowed_billing_countries[198]}", "${json.allowed_billing_countries[199]}", "${json.allowed_billing_countries[200]}", "${json.allowed_billing_countries[201]}", "${json.allowed_billing_countries[202]}", "${json.allowed_billing_countries[203]}", "${json.allowed_billing_countries[204]}", "${json.allowed_billing_countries[205]}", "${json.allowed_billing_countries[206]}", "${json.allowed_billing_countries[207]}", "${json.allowed_billing_countries[208]}", "${json.allowed_billing_countries[209]}", "${json.allowed_billing_countries[210]}"],
+ "allowed_shipping_countries": ["${json.allowed_shipping_countries[0]}", "${json.allowed_shipping_countries[1]}", "${json.allowed_shipping_countries[2]}", "${json.allowed_shipping_countries[3]}", "${json.allowed_shipping_countries[4]}", "${json.allowed_shipping_countries[5]}", "${json.allowed_shipping_countries[6]}", "${json.allowed_shipping_countries[7]}", "${json.allowed_shipping_countries[8]}", "${json.allowed_shipping_countries[9]}", "${json.allowed_shipping_countries[10]}", "${json.allowed_shipping_countries[11]}", "${json.allowed_shipping_countries[12]}", "${json.allowed_shipping_countries[13]}", "${json.allowed_shipping_countries[14]}", "${json.allowed_shipping_countries[15]}", "${json.allowed_shipping_countries[16]}", "${json.allowed_shipping_countries[17]}", "${json.allowed_shipping_countries[18]}", "${json.allowed_shipping_countries[19]}", "${json.allowed_shipping_countries[20]}", "${json.allowed_shipping_countries[21]}", "${json.allowed_shipping_countries[22]}", "${json.allowed_shipping_countries[23]}", "${json.allowed_shipping_countries[24]}", "${json.allowed_shipping_countries[25]}", "${json.allowed_shipping_countries[26]}", "${json.allowed_shipping_countries[27]}", "${json.allowed_shipping_countries[28]}", "${json.allowed_shipping_countries[29]}", "${json.allowed_shipping_countries[30]}", "${json.allowed_shipping_countries[31]}", "${json.allowed_shipping_countries[32]}", "${json.allowed_shipping_countries[33]}", "${json.allowed_shipping_countries[34]}", "${json.allowed_shipping_countries[35]}", "${json.allowed_shipping_countries[36]}", "${json.allowed_shipping_countries[37]}", "${json.allowed_shipping_countries[38]}", "${json.allowed_shipping_countries[39]}", "${json.allowed_shipping_countries[40]}", "${json.allowed_shipping_countries[41]}", "${json.allowed_shipping_countries[42]}", "${json.allowed_shipping_countries[43]}", "${json.allowed_shipping_countries[44]}", "${json.allowed_shipping_countries[45]}", "${json.allowed_shipping_countries[46]}", "${json.allowed_shipping_countries[47]}", "${json.allowed_shipping_countries[48]}", "${json.allowed_shipping_countries[49]}", "${json.allowed_shipping_countries[50]}", "${json.allowed_shipping_countries[51]}", "${json.allowed_shipping_countries[52]}", "${json.allowed_shipping_countries[53]}", "${json.allowed_shipping_countries[54]}", "${json.allowed_shipping_countries[55]}", "${json.allowed_shipping_countries[56]}", "${json.allowed_shipping_countries[57]}", "${json.allowed_shipping_countries[58]}", "${json.allowed_shipping_countries[59]}", "${json.allowed_shipping_countries[60]}", "${json.allowed_shipping_countries[61]}", "${json.allowed_shipping_countries[62]}", "${json.allowed_shipping_countries[63]}", "${json.allowed_shipping_countries[64]}", "${json.allowed_shipping_countries[65]}", "${json.allowed_shipping_countries[66]}", "${json.allowed_shipping_countries[67]}", "${json.allowed_shipping_countries[68]}", "${json.allowed_shipping_countries[69]}", "${json.allowed_shipping_countries[70]}", "${json.allowed_shipping_countries[71]}", "${json.allowed_shipping_countries[72]}", "${json.allowed_shipping_countries[73]}", "${json.allowed_shipping_countries[74]}", "${json.allowed_shipping_countries[75]}", "${json.allowed_shipping_countries[76]}", "${json.allowed_shipping_countries[77]}", "${json.allowed_shipping_countries[78]}", "${json.allowed_shipping_countries[79]}", "${json.allowed_shipping_countries[80]}", "${json.allowed_shipping_countries[81]}", "${json.allowed_shipping_countries[82]}", "${json.allowed_shipping_countries[83]}", "${json.allowed_shipping_countries[84]}", "${json.allowed_shipping_countries[85]}", "${json.allowed_shipping_countries[86]}", "${json.allowed_shipping_countries[87]}", "${json.allowed_shipping_countries[88]}", "${json.allowed_shipping_countries[89]}", "${json.allowed_shipping_countries[90]}", "${json.allowed_shipping_countries[91]}", "${json.allowed_shipping_countries[92]}", "${json.allowed_shipping_countries[93]}", "${json.allowed_shipping_countries[94]}", "${json.allowed_shipping_countries[95]}", "${json.allowed_shipping_countries[96]}", "${json.allowed_shipping_countries[97]}", "${json.allowed_shipping_countries[98]}", "${json.allowed_shipping_countries[99]}", "${json.allowed_shipping_countries[100]}", "${json.allowed_shipping_countries[101]}", "${json.allowed_shipping_countries[102]}", "${json.allowed_shipping_countries[103]}", "${json.allowed_shipping_countries[104]}", "${json.allowed_shipping_countries[105]}", "${json.allowed_shipping_countries[106]}", "${json.allowed_shipping_countries[107]}", "${json.allowed_shipping_countries[108]}", "${json.allowed_shipping_countries[109]}", "${json.allowed_shipping_countries[110]}", "${json.allowed_shipping_countries[111]}", "${json.allowed_shipping_countries[112]}", "${json.allowed_shipping_countries[113]}", "${json.allowed_shipping_countries[114]}", "${json.allowed_shipping_countries[115]}", "${json.allowed_shipping_countries[116]}", "${json.allowed_shipping_countries[117]}", "${json.allowed_shipping_countries[118]}", "${json.allowed_shipping_countries[119]}", "${json.allowed_shipping_countries[120]}", "${json.allowed_shipping_countries[121]}", "${json.allowed_shipping_countries[122]}", "${json.allowed_shipping_countries[123]}", "${json.allowed_shipping_countries[124]}", "${json.allowed_shipping_countries[125]}", "${json.allowed_shipping_countries[126]}", "${json.allowed_shipping_countries[127]}", "${json.allowed_shipping_countries[128]}", "${json.allowed_shipping_countries[129]}", "${json.allowed_shipping_countries[130]}", "${json.allowed_shipping_countries[131]}", "${json.allowed_shipping_countries[132]}", "${json.allowed_shipping_countries[133]}", "${json.allowed_shipping_countries[134]}", "${json.allowed_shipping_countries[135]}", "${json.allowed_shipping_countries[136]}", "${json.allowed_shipping_countries[137]}", "${json.allowed_shipping_countries[138]}", "${json.allowed_shipping_countries[139]}", "${json.allowed_shipping_countries[140]}", "${json.allowed_shipping_countries[141]}", "${json.allowed_shipping_countries[142]}", "${json.allowed_shipping_countries[143]}", "${json.allowed_shipping_countries[144]}", "${json.allowed_shipping_countries[145]}", "${json.allowed_shipping_countries[146]}", "${json.allowed_shipping_countries[147]}", "${json.allowed_shipping_countries[148]}", "${json.allowed_shipping_countries[149]}", "${json.allowed_shipping_countries[150]}", "${json.allowed_shipping_countries[151]}", "${json.allowed_shipping_countries[152]}", "${json.allowed_shipping_countries[153]}", "${json.allowed_shipping_countries[154]}", "${json.allowed_shipping_countries[155]}", "${json.allowed_shipping_countries[156]}", "${json.allowed_shipping_countries[157]}", "${json.allowed_shipping_countries[158]}", "${json.allowed_shipping_countries[159]}", "${json.allowed_shipping_countries[160]}", "${json.allowed_shipping_countries[161]}", "${json.allowed_shipping_countries[162]}", "${json.allowed_shipping_countries[163]}", "${json.allowed_shipping_countries[164]}", "${json.allowed_shipping_countries[165]}", "${json.allowed_shipping_countries[166]}", "${json.allowed_shipping_countries[167]}", "${json.allowed_shipping_countries[168]}", "${json.allowed_shipping_countries[169]}", "${json.allowed_shipping_countries[170]}", "${json.allowed_shipping_countries[171]}", "${json.allowed_shipping_countries[172]}", "${json.allowed_shipping_countries[173]}", "${json.allowed_shipping_countries[174]}", "${json.allowed_shipping_countries[175]}", "${json.allowed_shipping_countries[176]}", "${json.allowed_shipping_countries[177]}", "${json.allowed_shipping_countries[178]}", "${json.allowed_shipping_countries[179]}", "${json.allowed_shipping_countries[180]}", "${json.allowed_shipping_countries[181]}", "${json.allowed_shipping_countries[182]}", "${json.allowed_shipping_countries[183]}", "${json.allowed_shipping_countries[184]}", "${json.allowed_shipping_countries[185]}", "${json.allowed_shipping_countries[186]}", "${json.allowed_shipping_countries[187]}", "${json.allowed_shipping_countries[188]}", "${json.allowed_shipping_countries[189]}", "${json.allowed_shipping_countries[190]}", "${json.allowed_shipping_countries[191]}", "${json.allowed_shipping_countries[192]}", "${json.allowed_shipping_countries[193]}", "${json.allowed_shipping_countries[194]}", "${json.allowed_shipping_countries[195]}", "${json.allowed_shipping_countries[196]}", "${json.allowed_shipping_countries[197]}", "${json.allowed_shipping_countries[198]}", "${json.allowed_shipping_countries[199]}", "${json.allowed_shipping_countries[200]}", "${json.allowed_shipping_countries[201]}", "${json.allowed_shipping_countries[202]}", "${json.allowed_shipping_countries[203]}", "${json.allowed_shipping_countries[204]}", "${json.allowed_shipping_countries[205]}", "${json.allowed_shipping_countries[206]}", "${json.allowed_shipping_countries[207]}", "${json.allowed_shipping_countries[208]}", "${json.allowed_shipping_countries[209]}", "${json.allowed_shipping_countries[210]}"],
"cart": {
"items": [
{
- "image_url": "${json.cart.items[0].image_url}",
- "name": "${json.cart.items[0].name}",
- "product_url": "${json.cart.items[0].product_url}",
- "quantity": "${json.cart.items[0].quantity}",
- "reference": "${json.cart.items[0].reference}",
- "tax_rate": "${json.cart.items[0].tax_rate}",
- "total_price_excluding_tax": "${json.cart.items[0].total_price_excluding_tax}",
- "total_price_including_tax": "${json.cart.items[0].total_price_including_tax}",
- "total_tax_amount": "${json.cart.items[0].total_tax_amount}",
- "type": "${json.cart.items[0].type}",
+ "image_url": "${json.cart.items[0].image_url}",
+ "name": "${json.cart.items[0].name}",
+ "product_url": "${json.cart.items[0].product_url}",
+ "quantity": "${json.cart.items[0].quantity}",
+ "reference": "${json.cart.items[0].reference}",
+ "tax_rate": "${json.cart.items[0].tax_rate}",
+ "total_price_excluding_tax": "${json.cart.items[0].total_price_excluding_tax}",
+ "total_price_including_tax": "${json.cart.items[0].total_price_including_tax}",
+ "total_tax_amount": "${json.cart.items[0].total_tax_amount}",
+ "type": "${json.cart.items[0].type}",
"unit_price": "${json.cart.items[0].unit_price}"
}
- ],
- "subtotal": "${json.cart.subtotal}",
- "total_discount_amount_excluding_tax": "${json.cart.total_discount_amount_excluding_tax}",
- "total_price_excluding_tax": "${json.cart.total_price_excluding_tax}",
- "total_price_including_tax": "${json.cart.total_price_including_tax}",
- "total_shipping_amount_excluding_tax": "${json.cart.total_shipping_amount_excluding_tax}",
- "total_store_credit": "${json.cart.total_store_credit}",
- "total_surcharge_amount_excluding_tax": "${json.cart.total_surcharge_amount_excluding_tax}",
+ ],
+ "subtotal": "${json.cart.subtotal}",
+ "total_discount_amount_excluding_tax": "${json.cart.total_discount_amount_excluding_tax}",
+ "total_price_excluding_tax": "${json.cart.total_price_excluding_tax}",
+ "total_price_including_tax": "${json.cart.total_price_including_tax}",
+ "total_shipping_amount_excluding_tax": "${json.cart.total_shipping_amount_excluding_tax}",
+ "total_store_credit": "${json.cart.total_store_credit}",
+ "total_surcharge_amount_excluding_tax": "${json.cart.total_surcharge_amount_excluding_tax}",
"total_tax_amount": "${json.cart.total_tax_amount}"
- },
+ },
"merchant_urls": {
- "checkout": "${json.merchant_urls.checkout}",
- "confirmation": "${json.merchant_urls.confirmation}",
+ "checkout": "${json.merchant_urls.checkout}",
+ "confirmation": "${json.merchant_urls.confirmation}",
"terms": "${json.merchant_urls.terms}"
- },
+ },
"options": {
- "allow_separate_shipping_address": "${json.options.allow_separate_shipping_address}",
- "allowed_customer_types": ["${json.options.allowed_customer_types[0]}"],
- "date_of_birth_mandatory": "${json.options.date_of_birth_mandatory}",
- "national_identification_number_mandatory": "${json.options.national_identification_number_mandatory}",
+ "allow_separate_shipping_address": "${json.options.allow_separate_shipping_address}",
+ "allowed_customer_types": ["${json.options.allowed_customer_types[0]}"],
+ "date_of_birth_mandatory": "${json.options.date_of_birth_mandatory}",
+ "national_identification_number_mandatory": "${json.options.national_identification_number_mandatory}",
"payment_selector_on_load": "${json.options.payment_selector_on_load}"
- },
+ },
"preview_payment_methods": [
{
"data": {
"days": "${json.preview_payment_methods[0].data.days}"
- },
- "id": "${json.preview_payment_methods[0].id}",
+ },
+ "id": "${json.preview_payment_methods[0].id}",
"type": "${json.preview_payment_methods[0].type}"
},
{
"data": {
- "allow_saved_card": "${json.preview_payment_methods[1].data.allow_saved_card}",
- "available_cards": ["${json.preview_payment_methods[1].data.available_cards[0]}", "${json.preview_payment_methods[1].data.available_cards[1]}"],
+ "allow_saved_card": "${json.preview_payment_methods[1].data.allow_saved_card}",
+ "available_cards": ["${json.preview_payment_methods[1].data.available_cards[0]}", "${json.preview_payment_methods[1].data.available_cards[1]}"],
"do_save_card": "${json.preview_payment_methods[1].data.do_save_card}"
- },
- "id": "${json.preview_payment_methods[1].id}",
+ },
+ "id": "${json.preview_payment_methods[1].id}",
"type": "${json.preview_payment_methods[1].type}"
}
- ],
- "required_fields": ["${json.required_fields[0]}", "${json.required_fields[1]}"],
+ ],
+ "required_fields": ["${json.required_fields[0]}", "${json.required_fields[1]}"],
"shared": {
"billing_address": {
"country": "${json.shared.billing_address.country}"
- },
+ },
"challenge": {
- "country": "${json.shared.challenge.country}",
- "email": "drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com",
+ "country": "${json.shared.challenge.country}",
+ "email": "drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com",
"postal_code": "10066"
- },
- "currency": "${json.shared.currency}",
+ },
+ "currency": "${json.shared.currency}",
"customer": {
"type": "${json.shared.customer.type}"
- },
+ },
"language": "${json.shared.language}"
- },
+ },
"status": {
- "prescreened": "${json.status.prescreened}",
+ "prescreened": "${json.status.prescreened}",
"require_terms_consent": "${json.status.require_terms_consent}"
}
}`,
@@ -186,92 +186,92 @@ export default function() {
// Request #4
res = http.post("https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25",
`{
- "allowed_billing_countries": ["${json.allowed_billing_countries[0]}", "${json.allowed_billing_countries[1]}", "${json.allowed_billing_countries[2]}", "${json.allowed_billing_countries[3]}", "${json.allowed_billing_countries[4]}", "${json.allowed_billing_countries[5]}", "${json.allowed_billing_countries[6]}", "${json.allowed_billing_countries[7]}", "${json.allowed_billing_countries[8]}", "${json.allowed_billing_countries[9]}", "${json.allowed_billing_countries[10]}", "${json.allowed_billing_countries[11]}", "${json.allowed_billing_countries[12]}", "${json.allowed_billing_countries[13]}", "${json.allowed_billing_countries[14]}", "${json.allowed_billing_countries[15]}", "${json.allowed_billing_countries[16]}", "${json.allowed_billing_countries[17]}", "${json.allowed_billing_countries[18]}", "${json.allowed_billing_countries[19]}", "${json.allowed_billing_countries[20]}", "${json.allowed_billing_countries[21]}", "${json.allowed_billing_countries[22]}", "${json.allowed_billing_countries[23]}", "${json.allowed_billing_countries[24]}", "${json.allowed_billing_countries[25]}", "${json.allowed_billing_countries[26]}", "${json.allowed_billing_countries[27]}", "${json.allowed_billing_countries[28]}", "${json.allowed_billing_countries[29]}", "${json.allowed_billing_countries[30]}", "${json.allowed_billing_countries[31]}", "${json.allowed_billing_countries[32]}", "${json.allowed_billing_countries[33]}", "${json.allowed_billing_countries[34]}", "${json.allowed_billing_countries[35]}", "${json.allowed_billing_countries[36]}", "${json.allowed_billing_countries[37]}", "${json.allowed_billing_countries[38]}", "${json.allowed_billing_countries[39]}", "${json.allowed_billing_countries[40]}", "${json.allowed_billing_countries[41]}", "${json.allowed_billing_countries[42]}", "${json.allowed_billing_countries[43]}", "${json.allowed_billing_countries[44]}", "${json.allowed_billing_countries[45]}", "${json.allowed_billing_countries[46]}", "${json.allowed_billing_countries[47]}", "${json.allowed_billing_countries[48]}", "${json.allowed_billing_countries[49]}", "${json.allowed_billing_countries[50]}", "${json.allowed_billing_countries[51]}", "${json.allowed_billing_countries[52]}", "${json.allowed_billing_countries[53]}", "${json.allowed_billing_countries[54]}", "${json.allowed_billing_countries[55]}", "${json.allowed_billing_countries[56]}", "${json.allowed_billing_countries[57]}", "${json.allowed_billing_countries[58]}", "${json.allowed_billing_countries[59]}", "${json.allowed_billing_countries[60]}", "${json.allowed_billing_countries[61]}", "${json.allowed_billing_countries[62]}", "${json.allowed_billing_countries[63]}", "${json.allowed_billing_countries[64]}", "${json.allowed_billing_countries[65]}", "${json.allowed_billing_countries[66]}", "${json.allowed_billing_countries[67]}", "${json.allowed_billing_countries[68]}", "${json.allowed_billing_countries[69]}", "${json.allowed_billing_countries[70]}", "${json.allowed_billing_countries[71]}", "${json.allowed_billing_countries[72]}", "${json.allowed_billing_countries[73]}", "${json.allowed_billing_countries[74]}", "${json.allowed_billing_countries[75]}", "${json.allowed_billing_countries[76]}", "${json.allowed_billing_countries[77]}", "${json.allowed_billing_countries[78]}", "${json.allowed_billing_countries[79]}", "${json.allowed_billing_countries[80]}", "${json.allowed_billing_countries[81]}", "${json.allowed_billing_countries[82]}", "${json.allowed_billing_countries[83]}", "${json.allowed_billing_countries[84]}", "${json.allowed_billing_countries[85]}", "${json.allowed_billing_countries[86]}", "${json.allowed_billing_countries[87]}", "${json.allowed_billing_countries[88]}", "${json.allowed_billing_countries[89]}", "${json.allowed_billing_countries[90]}", "${json.allowed_billing_countries[91]}", "${json.allowed_billing_countries[92]}", "${json.allowed_billing_countries[93]}", "${json.allowed_billing_countries[94]}", "${json.allowed_billing_countries[95]}", "${json.allowed_billing_countries[96]}", "${json.allowed_billing_countries[97]}", "${json.allowed_billing_countries[98]}", "${json.allowed_billing_countries[99]}", "${json.allowed_billing_countries[100]}", "${json.allowed_billing_countries[101]}", "${json.allowed_billing_countries[102]}", "${json.allowed_billing_countries[103]}", "${json.allowed_billing_countries[104]}", "${json.allowed_billing_countries[105]}", "${json.allowed_billing_countries[106]}", "${json.allowed_billing_countries[107]}", "${json.allowed_billing_countries[108]}", "${json.allowed_billing_countries[109]}", "${json.allowed_billing_countries[110]}", "${json.allowed_billing_countries[111]}", "${json.allowed_billing_countries[112]}", "${json.allowed_billing_countries[113]}", "${json.allowed_billing_countries[114]}", "${json.allowed_billing_countries[115]}", "${json.allowed_billing_countries[116]}", "${json.allowed_billing_countries[117]}", "${json.allowed_billing_countries[118]}", "${json.allowed_billing_countries[119]}", "${json.allowed_billing_countries[120]}", "${json.allowed_billing_countries[121]}", "${json.allowed_billing_countries[122]}", "${json.allowed_billing_countries[123]}", "${json.allowed_billing_countries[124]}", "${json.allowed_billing_countries[125]}", "${json.allowed_billing_countries[126]}", "${json.allowed_billing_countries[127]}", "${json.allowed_billing_countries[128]}", "${json.allowed_billing_countries[129]}", "${json.allowed_billing_countries[130]}", "${json.allowed_billing_countries[131]}", "${json.allowed_billing_countries[132]}", "${json.allowed_billing_countries[133]}", "${json.allowed_billing_countries[134]}", "${json.allowed_billing_countries[135]}", "${json.allowed_billing_countries[136]}", "${json.allowed_billing_countries[137]}", "${json.allowed_billing_countries[138]}", "${json.allowed_billing_countries[139]}", "${json.allowed_billing_countries[140]}", "${json.allowed_billing_countries[141]}", "${json.allowed_billing_countries[142]}", "${json.allowed_billing_countries[143]}", "${json.allowed_billing_countries[144]}", "${json.allowed_billing_countries[145]}", "${json.allowed_billing_countries[146]}", "${json.allowed_billing_countries[147]}", "${json.allowed_billing_countries[148]}", "${json.allowed_billing_countries[149]}", "${json.allowed_billing_countries[150]}", "${json.allowed_billing_countries[151]}", "${json.allowed_billing_countries[152]}", "${json.allowed_billing_countries[153]}", "${json.allowed_billing_countries[154]}", "${json.allowed_billing_countries[155]}", "${json.allowed_billing_countries[156]}", "${json.allowed_billing_countries[157]}", "${json.allowed_billing_countries[158]}", "${json.allowed_billing_countries[159]}", "${json.allowed_billing_countries[160]}", "${json.allowed_billing_countries[161]}", "${json.allowed_billing_countries[162]}", "${json.allowed_billing_countries[163]}", "${json.allowed_billing_countries[164]}", "${json.allowed_billing_countries[165]}", "${json.allowed_billing_countries[166]}", "${json.allowed_billing_countries[167]}", "${json.allowed_billing_countries[168]}", "${json.allowed_billing_countries[169]}", "${json.allowed_billing_countries[170]}", "${json.allowed_billing_countries[171]}", "${json.allowed_billing_countries[172]}", "${json.allowed_billing_countries[173]}", "${json.allowed_billing_countries[174]}", "${json.allowed_billing_countries[175]}", "${json.allowed_billing_countries[176]}", "${json.allowed_billing_countries[177]}", "${json.allowed_billing_countries[178]}", "${json.allowed_billing_countries[179]}", "${json.allowed_billing_countries[180]}", "${json.allowed_billing_countries[181]}", "${json.allowed_billing_countries[182]}", "${json.allowed_billing_countries[183]}", "${json.allowed_billing_countries[184]}", "${json.allowed_billing_countries[185]}", "${json.allowed_billing_countries[186]}", "${json.allowed_billing_countries[187]}", "${json.allowed_billing_countries[188]}", "${json.allowed_billing_countries[189]}", "${json.allowed_billing_countries[190]}", "${json.allowed_billing_countries[191]}", "${json.allowed_billing_countries[192]}", "${json.allowed_billing_countries[193]}", "${json.allowed_billing_countries[194]}", "${json.allowed_billing_countries[195]}", "${json.allowed_billing_countries[196]}", "${json.allowed_billing_countries[197]}", "${json.allowed_billing_countries[198]}", "${json.allowed_billing_countries[199]}", "${json.allowed_billing_countries[200]}", "${json.allowed_billing_countries[201]}", "${json.allowed_billing_countries[202]}", "${json.allowed_billing_countries[203]}", "${json.allowed_billing_countries[204]}", "${json.allowed_billing_countries[205]}", "${json.allowed_billing_countries[206]}", "${json.allowed_billing_countries[207]}", "${json.allowed_billing_countries[208]}", "${json.allowed_billing_countries[209]}", "${json.allowed_billing_countries[210]}"],
- "allowed_shipping_countries": ["${json.allowed_shipping_countries[0]}", "${json.allowed_shipping_countries[1]}", "${json.allowed_shipping_countries[2]}", "${json.allowed_shipping_countries[3]}", "${json.allowed_shipping_countries[4]}", "${json.allowed_shipping_countries[5]}", "${json.allowed_shipping_countries[6]}", "${json.allowed_shipping_countries[7]}", "${json.allowed_shipping_countries[8]}", "${json.allowed_shipping_countries[9]}", "${json.allowed_shipping_countries[10]}", "${json.allowed_shipping_countries[11]}", "${json.allowed_shipping_countries[12]}", "${json.allowed_shipping_countries[13]}", "${json.allowed_shipping_countries[14]}", "${json.allowed_shipping_countries[15]}", "${json.allowed_shipping_countries[16]}", "${json.allowed_shipping_countries[17]}", "${json.allowed_shipping_countries[18]}", "${json.allowed_shipping_countries[19]}", "${json.allowed_shipping_countries[20]}", "${json.allowed_shipping_countries[21]}", "${json.allowed_shipping_countries[22]}", "${json.allowed_shipping_countries[23]}", "${json.allowed_shipping_countries[24]}", "${json.allowed_shipping_countries[25]}", "${json.allowed_shipping_countries[26]}", "${json.allowed_shipping_countries[27]}", "${json.allowed_shipping_countries[28]}", "${json.allowed_shipping_countries[29]}", "${json.allowed_shipping_countries[30]}", "${json.allowed_shipping_countries[31]}", "${json.allowed_shipping_countries[32]}", "${json.allowed_shipping_countries[33]}", "${json.allowed_shipping_countries[34]}", "${json.allowed_shipping_countries[35]}", "${json.allowed_shipping_countries[36]}", "${json.allowed_shipping_countries[37]}", "${json.allowed_shipping_countries[38]}", "${json.allowed_shipping_countries[39]}", "${json.allowed_shipping_countries[40]}", "${json.allowed_shipping_countries[41]}", "${json.allowed_shipping_countries[42]}", "${json.allowed_shipping_countries[43]}", "${json.allowed_shipping_countries[44]}", "${json.allowed_shipping_countries[45]}", "${json.allowed_shipping_countries[46]}", "${json.allowed_shipping_countries[47]}", "${json.allowed_shipping_countries[48]}", "${json.allowed_shipping_countries[49]}", "${json.allowed_shipping_countries[50]}", "${json.allowed_shipping_countries[51]}", "${json.allowed_shipping_countries[52]}", "${json.allowed_shipping_countries[53]}", "${json.allowed_shipping_countries[54]}", "${json.allowed_shipping_countries[55]}", "${json.allowed_shipping_countries[56]}", "${json.allowed_shipping_countries[57]}", "${json.allowed_shipping_countries[58]}", "${json.allowed_shipping_countries[59]}", "${json.allowed_shipping_countries[60]}", "${json.allowed_shipping_countries[61]}", "${json.allowed_shipping_countries[62]}", "${json.allowed_shipping_countries[63]}", "${json.allowed_shipping_countries[64]}", "${json.allowed_shipping_countries[65]}", "${json.allowed_shipping_countries[66]}", "${json.allowed_shipping_countries[67]}", "${json.allowed_shipping_countries[68]}", "${json.allowed_shipping_countries[69]}", "${json.allowed_shipping_countries[70]}", "${json.allowed_shipping_countries[71]}", "${json.allowed_shipping_countries[72]}", "${json.allowed_shipping_countries[73]}", "${json.allowed_shipping_countries[74]}", "${json.allowed_shipping_countries[75]}", "${json.allowed_shipping_countries[76]}", "${json.allowed_shipping_countries[77]}", "${json.allowed_shipping_countries[78]}", "${json.allowed_shipping_countries[79]}", "${json.allowed_shipping_countries[80]}", "${json.allowed_shipping_countries[81]}", "${json.allowed_shipping_countries[82]}", "${json.allowed_shipping_countries[83]}", "${json.allowed_shipping_countries[84]}", "${json.allowed_shipping_countries[85]}", "${json.allowed_shipping_countries[86]}", "${json.allowed_shipping_countries[87]}", "${json.allowed_shipping_countries[88]}", "${json.allowed_shipping_countries[89]}", "${json.allowed_shipping_countries[90]}", "${json.allowed_shipping_countries[91]}", "${json.allowed_shipping_countries[92]}", "${json.allowed_shipping_countries[93]}", "${json.allowed_shipping_countries[94]}", "${json.allowed_shipping_countries[95]}", "${json.allowed_shipping_countries[96]}", "${json.allowed_shipping_countries[97]}", "${json.allowed_shipping_countries[98]}", "${json.allowed_shipping_countries[99]}", "${json.allowed_shipping_countries[100]}", "${json.allowed_shipping_countries[101]}", "${json.allowed_shipping_countries[102]}", "${json.allowed_shipping_countries[103]}", "${json.allowed_shipping_countries[104]}", "${json.allowed_shipping_countries[105]}", "${json.allowed_shipping_countries[106]}", "${json.allowed_shipping_countries[107]}", "${json.allowed_shipping_countries[108]}", "${json.allowed_shipping_countries[109]}", "${json.allowed_shipping_countries[110]}", "${json.allowed_shipping_countries[111]}", "${json.allowed_shipping_countries[112]}", "${json.allowed_shipping_countries[113]}", "${json.allowed_shipping_countries[114]}", "${json.allowed_shipping_countries[115]}", "${json.allowed_shipping_countries[116]}", "${json.allowed_shipping_countries[117]}", "${json.allowed_shipping_countries[118]}", "${json.allowed_shipping_countries[119]}", "${json.allowed_shipping_countries[120]}", "${json.allowed_shipping_countries[121]}", "${json.allowed_shipping_countries[122]}", "${json.allowed_shipping_countries[123]}", "${json.allowed_shipping_countries[124]}", "${json.allowed_shipping_countries[125]}", "${json.allowed_shipping_countries[126]}", "${json.allowed_shipping_countries[127]}", "${json.allowed_shipping_countries[128]}", "${json.allowed_shipping_countries[129]}", "${json.allowed_shipping_countries[130]}", "${json.allowed_shipping_countries[131]}", "${json.allowed_shipping_countries[132]}", "${json.allowed_shipping_countries[133]}", "${json.allowed_shipping_countries[134]}", "${json.allowed_shipping_countries[135]}", "${json.allowed_shipping_countries[136]}", "${json.allowed_shipping_countries[137]}", "${json.allowed_shipping_countries[138]}", "${json.allowed_shipping_countries[139]}", "${json.allowed_shipping_countries[140]}", "${json.allowed_shipping_countries[141]}", "${json.allowed_shipping_countries[142]}", "${json.allowed_shipping_countries[143]}", "${json.allowed_shipping_countries[144]}", "${json.allowed_shipping_countries[145]}", "${json.allowed_shipping_countries[146]}", "${json.allowed_shipping_countries[147]}", "${json.allowed_shipping_countries[148]}", "${json.allowed_shipping_countries[149]}", "${json.allowed_shipping_countries[150]}", "${json.allowed_shipping_countries[151]}", "${json.allowed_shipping_countries[152]}", "${json.allowed_shipping_countries[153]}", "${json.allowed_shipping_countries[154]}", "${json.allowed_shipping_countries[155]}", "${json.allowed_shipping_countries[156]}", "${json.allowed_shipping_countries[157]}", "${json.allowed_shipping_countries[158]}", "${json.allowed_shipping_countries[159]}", "${json.allowed_shipping_countries[160]}", "${json.allowed_shipping_countries[161]}", "${json.allowed_shipping_countries[162]}", "${json.allowed_shipping_countries[163]}", "${json.allowed_shipping_countries[164]}", "${json.allowed_shipping_countries[165]}", "${json.allowed_shipping_countries[166]}", "${json.allowed_shipping_countries[167]}", "${json.allowed_shipping_countries[168]}", "${json.allowed_shipping_countries[169]}", "${json.allowed_shipping_countries[170]}", "${json.allowed_shipping_countries[171]}", "${json.allowed_shipping_countries[172]}", "${json.allowed_shipping_countries[173]}", "${json.allowed_shipping_countries[174]}", "${json.allowed_shipping_countries[175]}", "${json.allowed_shipping_countries[176]}", "${json.allowed_shipping_countries[177]}", "${json.allowed_shipping_countries[178]}", "${json.allowed_shipping_countries[179]}", "${json.allowed_shipping_countries[180]}", "${json.allowed_shipping_countries[181]}", "${json.allowed_shipping_countries[182]}", "${json.allowed_shipping_countries[183]}", "${json.allowed_shipping_countries[184]}", "${json.allowed_shipping_countries[185]}", "${json.allowed_shipping_countries[186]}", "${json.allowed_shipping_countries[187]}", "${json.allowed_shipping_countries[188]}", "${json.allowed_shipping_countries[189]}", "${json.allowed_shipping_countries[190]}", "${json.allowed_shipping_countries[191]}", "${json.allowed_shipping_countries[192]}", "${json.allowed_shipping_countries[193]}", "${json.allowed_shipping_countries[194]}", "${json.allowed_shipping_countries[195]}", "${json.allowed_shipping_countries[196]}", "${json.allowed_shipping_countries[197]}", "${json.allowed_shipping_countries[198]}", "${json.allowed_shipping_countries[199]}", "${json.allowed_shipping_countries[200]}", "${json.allowed_shipping_countries[201]}", "${json.allowed_shipping_countries[202]}", "${json.allowed_shipping_countries[203]}", "${json.allowed_shipping_countries[204]}", "${json.allowed_shipping_countries[205]}", "${json.allowed_shipping_countries[206]}", "${json.allowed_shipping_countries[207]}", "${json.allowed_shipping_countries[208]}", "${json.allowed_shipping_countries[209]}", "${json.allowed_shipping_countries[210]}"],
- "analytics_user_id": "${json.analytics_user_id}",
+ "allowed_billing_countries": ["${json.allowed_billing_countries[0]}", "${json.allowed_billing_countries[1]}", "${json.allowed_billing_countries[2]}", "${json.allowed_billing_countries[3]}", "${json.allowed_billing_countries[4]}", "${json.allowed_billing_countries[5]}", "${json.allowed_billing_countries[6]}", "${json.allowed_billing_countries[7]}", "${json.allowed_billing_countries[8]}", "${json.allowed_billing_countries[9]}", "${json.allowed_billing_countries[10]}", "${json.allowed_billing_countries[11]}", "${json.allowed_billing_countries[12]}", "${json.allowed_billing_countries[13]}", "${json.allowed_billing_countries[14]}", "${json.allowed_billing_countries[15]}", "${json.allowed_billing_countries[16]}", "${json.allowed_billing_countries[17]}", "${json.allowed_billing_countries[18]}", "${json.allowed_billing_countries[19]}", "${json.allowed_billing_countries[20]}", "${json.allowed_billing_countries[21]}", "${json.allowed_billing_countries[22]}", "${json.allowed_billing_countries[23]}", "${json.allowed_billing_countries[24]}", "${json.allowed_billing_countries[25]}", "${json.allowed_billing_countries[26]}", "${json.allowed_billing_countries[27]}", "${json.allowed_billing_countries[28]}", "${json.allowed_billing_countries[29]}", "${json.allowed_billing_countries[30]}", "${json.allowed_billing_countries[31]}", "${json.allowed_billing_countries[32]}", "${json.allowed_billing_countries[33]}", "${json.allowed_billing_countries[34]}", "${json.allowed_billing_countries[35]}", "${json.allowed_billing_countries[36]}", "${json.allowed_billing_countries[37]}", "${json.allowed_billing_countries[38]}", "${json.allowed_billing_countries[39]}", "${json.allowed_billing_countries[40]}", "${json.allowed_billing_countries[41]}", "${json.allowed_billing_countries[42]}", "${json.allowed_billing_countries[43]}", "${json.allowed_billing_countries[44]}", "${json.allowed_billing_countries[45]}", "${json.allowed_billing_countries[46]}", "${json.allowed_billing_countries[47]}", "${json.allowed_billing_countries[48]}", "${json.allowed_billing_countries[49]}", "${json.allowed_billing_countries[50]}", "${json.allowed_billing_countries[51]}", "${json.allowed_billing_countries[52]}", "${json.allowed_billing_countries[53]}", "${json.allowed_billing_countries[54]}", "${json.allowed_billing_countries[55]}", "${json.allowed_billing_countries[56]}", "${json.allowed_billing_countries[57]}", "${json.allowed_billing_countries[58]}", "${json.allowed_billing_countries[59]}", "${json.allowed_billing_countries[60]}", "${json.allowed_billing_countries[61]}", "${json.allowed_billing_countries[62]}", "${json.allowed_billing_countries[63]}", "${json.allowed_billing_countries[64]}", "${json.allowed_billing_countries[65]}", "${json.allowed_billing_countries[66]}", "${json.allowed_billing_countries[67]}", "${json.allowed_billing_countries[68]}", "${json.allowed_billing_countries[69]}", "${json.allowed_billing_countries[70]}", "${json.allowed_billing_countries[71]}", "${json.allowed_billing_countries[72]}", "${json.allowed_billing_countries[73]}", "${json.allowed_billing_countries[74]}", "${json.allowed_billing_countries[75]}", "${json.allowed_billing_countries[76]}", "${json.allowed_billing_countries[77]}", "${json.allowed_billing_countries[78]}", "${json.allowed_billing_countries[79]}", "${json.allowed_billing_countries[80]}", "${json.allowed_billing_countries[81]}", "${json.allowed_billing_countries[82]}", "${json.allowed_billing_countries[83]}", "${json.allowed_billing_countries[84]}", "${json.allowed_billing_countries[85]}", "${json.allowed_billing_countries[86]}", "${json.allowed_billing_countries[87]}", "${json.allowed_billing_countries[88]}", "${json.allowed_billing_countries[89]}", "${json.allowed_billing_countries[90]}", "${json.allowed_billing_countries[91]}", "${json.allowed_billing_countries[92]}", "${json.allowed_billing_countries[93]}", "${json.allowed_billing_countries[94]}", "${json.allowed_billing_countries[95]}", "${json.allowed_billing_countries[96]}", "${json.allowed_billing_countries[97]}", "${json.allowed_billing_countries[98]}", "${json.allowed_billing_countries[99]}", "${json.allowed_billing_countries[100]}", "${json.allowed_billing_countries[101]}", "${json.allowed_billing_countries[102]}", "${json.allowed_billing_countries[103]}", "${json.allowed_billing_countries[104]}", "${json.allowed_billing_countries[105]}", "${json.allowed_billing_countries[106]}", "${json.allowed_billing_countries[107]}", "${json.allowed_billing_countries[108]}", "${json.allowed_billing_countries[109]}", "${json.allowed_billing_countries[110]}", "${json.allowed_billing_countries[111]}", "${json.allowed_billing_countries[112]}", "${json.allowed_billing_countries[113]}", "${json.allowed_billing_countries[114]}", "${json.allowed_billing_countries[115]}", "${json.allowed_billing_countries[116]}", "${json.allowed_billing_countries[117]}", "${json.allowed_billing_countries[118]}", "${json.allowed_billing_countries[119]}", "${json.allowed_billing_countries[120]}", "${json.allowed_billing_countries[121]}", "${json.allowed_billing_countries[122]}", "${json.allowed_billing_countries[123]}", "${json.allowed_billing_countries[124]}", "${json.allowed_billing_countries[125]}", "${json.allowed_billing_countries[126]}", "${json.allowed_billing_countries[127]}", "${json.allowed_billing_countries[128]}", "${json.allowed_billing_countries[129]}", "${json.allowed_billing_countries[130]}", "${json.allowed_billing_countries[131]}", "${json.allowed_billing_countries[132]}", "${json.allowed_billing_countries[133]}", "${json.allowed_billing_countries[134]}", "${json.allowed_billing_countries[135]}", "${json.allowed_billing_countries[136]}", "${json.allowed_billing_countries[137]}", "${json.allowed_billing_countries[138]}", "${json.allowed_billing_countries[139]}", "${json.allowed_billing_countries[140]}", "${json.allowed_billing_countries[141]}", "${json.allowed_billing_countries[142]}", "${json.allowed_billing_countries[143]}", "${json.allowed_billing_countries[144]}", "${json.allowed_billing_countries[145]}", "${json.allowed_billing_countries[146]}", "${json.allowed_billing_countries[147]}", "${json.allowed_billing_countries[148]}", "${json.allowed_billing_countries[149]}", "${json.allowed_billing_countries[150]}", "${json.allowed_billing_countries[151]}", "${json.allowed_billing_countries[152]}", "${json.allowed_billing_countries[153]}", "${json.allowed_billing_countries[154]}", "${json.allowed_billing_countries[155]}", "${json.allowed_billing_countries[156]}", "${json.allowed_billing_countries[157]}", "${json.allowed_billing_countries[158]}", "${json.allowed_billing_countries[159]}", "${json.allowed_billing_countries[160]}", "${json.allowed_billing_countries[161]}", "${json.allowed_billing_countries[162]}", "${json.allowed_billing_countries[163]}", "${json.allowed_billing_countries[164]}", "${json.allowed_billing_countries[165]}", "${json.allowed_billing_countries[166]}", "${json.allowed_billing_countries[167]}", "${json.allowed_billing_countries[168]}", "${json.allowed_billing_countries[169]}", "${json.allowed_billing_countries[170]}", "${json.allowed_billing_countries[171]}", "${json.allowed_billing_countries[172]}", "${json.allowed_billing_countries[173]}", "${json.allowed_billing_countries[174]}", "${json.allowed_billing_countries[175]}", "${json.allowed_billing_countries[176]}", "${json.allowed_billing_countries[177]}", "${json.allowed_billing_countries[178]}", "${json.allowed_billing_countries[179]}", "${json.allowed_billing_countries[180]}", "${json.allowed_billing_countries[181]}", "${json.allowed_billing_countries[182]}", "${json.allowed_billing_countries[183]}", "${json.allowed_billing_countries[184]}", "${json.allowed_billing_countries[185]}", "${json.allowed_billing_countries[186]}", "${json.allowed_billing_countries[187]}", "${json.allowed_billing_countries[188]}", "${json.allowed_billing_countries[189]}", "${json.allowed_billing_countries[190]}", "${json.allowed_billing_countries[191]}", "${json.allowed_billing_countries[192]}", "${json.allowed_billing_countries[193]}", "${json.allowed_billing_countries[194]}", "${json.allowed_billing_countries[195]}", "${json.allowed_billing_countries[196]}", "${json.allowed_billing_countries[197]}", "${json.allowed_billing_countries[198]}", "${json.allowed_billing_countries[199]}", "${json.allowed_billing_countries[200]}", "${json.allowed_billing_countries[201]}", "${json.allowed_billing_countries[202]}", "${json.allowed_billing_countries[203]}", "${json.allowed_billing_countries[204]}", "${json.allowed_billing_countries[205]}", "${json.allowed_billing_countries[206]}", "${json.allowed_billing_countries[207]}", "${json.allowed_billing_countries[208]}", "${json.allowed_billing_countries[209]}", "${json.allowed_billing_countries[210]}"],
+ "allowed_shipping_countries": ["${json.allowed_shipping_countries[0]}", "${json.allowed_shipping_countries[1]}", "${json.allowed_shipping_countries[2]}", "${json.allowed_shipping_countries[3]}", "${json.allowed_shipping_countries[4]}", "${json.allowed_shipping_countries[5]}", "${json.allowed_shipping_countries[6]}", "${json.allowed_shipping_countries[7]}", "${json.allowed_shipping_countries[8]}", "${json.allowed_shipping_countries[9]}", "${json.allowed_shipping_countries[10]}", "${json.allowed_shipping_countries[11]}", "${json.allowed_shipping_countries[12]}", "${json.allowed_shipping_countries[13]}", "${json.allowed_shipping_countries[14]}", "${json.allowed_shipping_countries[15]}", "${json.allowed_shipping_countries[16]}", "${json.allowed_shipping_countries[17]}", "${json.allowed_shipping_countries[18]}", "${json.allowed_shipping_countries[19]}", "${json.allowed_shipping_countries[20]}", "${json.allowed_shipping_countries[21]}", "${json.allowed_shipping_countries[22]}", "${json.allowed_shipping_countries[23]}", "${json.allowed_shipping_countries[24]}", "${json.allowed_shipping_countries[25]}", "${json.allowed_shipping_countries[26]}", "${json.allowed_shipping_countries[27]}", "${json.allowed_shipping_countries[28]}", "${json.allowed_shipping_countries[29]}", "${json.allowed_shipping_countries[30]}", "${json.allowed_shipping_countries[31]}", "${json.allowed_shipping_countries[32]}", "${json.allowed_shipping_countries[33]}", "${json.allowed_shipping_countries[34]}", "${json.allowed_shipping_countries[35]}", "${json.allowed_shipping_countries[36]}", "${json.allowed_shipping_countries[37]}", "${json.allowed_shipping_countries[38]}", "${json.allowed_shipping_countries[39]}", "${json.allowed_shipping_countries[40]}", "${json.allowed_shipping_countries[41]}", "${json.allowed_shipping_countries[42]}", "${json.allowed_shipping_countries[43]}", "${json.allowed_shipping_countries[44]}", "${json.allowed_shipping_countries[45]}", "${json.allowed_shipping_countries[46]}", "${json.allowed_shipping_countries[47]}", "${json.allowed_shipping_countries[48]}", "${json.allowed_shipping_countries[49]}", "${json.allowed_shipping_countries[50]}", "${json.allowed_shipping_countries[51]}", "${json.allowed_shipping_countries[52]}", "${json.allowed_shipping_countries[53]}", "${json.allowed_shipping_countries[54]}", "${json.allowed_shipping_countries[55]}", "${json.allowed_shipping_countries[56]}", "${json.allowed_shipping_countries[57]}", "${json.allowed_shipping_countries[58]}", "${json.allowed_shipping_countries[59]}", "${json.allowed_shipping_countries[60]}", "${json.allowed_shipping_countries[61]}", "${json.allowed_shipping_countries[62]}", "${json.allowed_shipping_countries[63]}", "${json.allowed_shipping_countries[64]}", "${json.allowed_shipping_countries[65]}", "${json.allowed_shipping_countries[66]}", "${json.allowed_shipping_countries[67]}", "${json.allowed_shipping_countries[68]}", "${json.allowed_shipping_countries[69]}", "${json.allowed_shipping_countries[70]}", "${json.allowed_shipping_countries[71]}", "${json.allowed_shipping_countries[72]}", "${json.allowed_shipping_countries[73]}", "${json.allowed_shipping_countries[74]}", "${json.allowed_shipping_countries[75]}", "${json.allowed_shipping_countries[76]}", "${json.allowed_shipping_countries[77]}", "${json.allowed_shipping_countries[78]}", "${json.allowed_shipping_countries[79]}", "${json.allowed_shipping_countries[80]}", "${json.allowed_shipping_countries[81]}", "${json.allowed_shipping_countries[82]}", "${json.allowed_shipping_countries[83]}", "${json.allowed_shipping_countries[84]}", "${json.allowed_shipping_countries[85]}", "${json.allowed_shipping_countries[86]}", "${json.allowed_shipping_countries[87]}", "${json.allowed_shipping_countries[88]}", "${json.allowed_shipping_countries[89]}", "${json.allowed_shipping_countries[90]}", "${json.allowed_shipping_countries[91]}", "${json.allowed_shipping_countries[92]}", "${json.allowed_shipping_countries[93]}", "${json.allowed_shipping_countries[94]}", "${json.allowed_shipping_countries[95]}", "${json.allowed_shipping_countries[96]}", "${json.allowed_shipping_countries[97]}", "${json.allowed_shipping_countries[98]}", "${json.allowed_shipping_countries[99]}", "${json.allowed_shipping_countries[100]}", "${json.allowed_shipping_countries[101]}", "${json.allowed_shipping_countries[102]}", "${json.allowed_shipping_countries[103]}", "${json.allowed_shipping_countries[104]}", "${json.allowed_shipping_countries[105]}", "${json.allowed_shipping_countries[106]}", "${json.allowed_shipping_countries[107]}", "${json.allowed_shipping_countries[108]}", "${json.allowed_shipping_countries[109]}", "${json.allowed_shipping_countries[110]}", "${json.allowed_shipping_countries[111]}", "${json.allowed_shipping_countries[112]}", "${json.allowed_shipping_countries[113]}", "${json.allowed_shipping_countries[114]}", "${json.allowed_shipping_countries[115]}", "${json.allowed_shipping_countries[116]}", "${json.allowed_shipping_countries[117]}", "${json.allowed_shipping_countries[118]}", "${json.allowed_shipping_countries[119]}", "${json.allowed_shipping_countries[120]}", "${json.allowed_shipping_countries[121]}", "${json.allowed_shipping_countries[122]}", "${json.allowed_shipping_countries[123]}", "${json.allowed_shipping_countries[124]}", "${json.allowed_shipping_countries[125]}", "${json.allowed_shipping_countries[126]}", "${json.allowed_shipping_countries[127]}", "${json.allowed_shipping_countries[128]}", "${json.allowed_shipping_countries[129]}", "${json.allowed_shipping_countries[130]}", "${json.allowed_shipping_countries[131]}", "${json.allowed_shipping_countries[132]}", "${json.allowed_shipping_countries[133]}", "${json.allowed_shipping_countries[134]}", "${json.allowed_shipping_countries[135]}", "${json.allowed_shipping_countries[136]}", "${json.allowed_shipping_countries[137]}", "${json.allowed_shipping_countries[138]}", "${json.allowed_shipping_countries[139]}", "${json.allowed_shipping_countries[140]}", "${json.allowed_shipping_countries[141]}", "${json.allowed_shipping_countries[142]}", "${json.allowed_shipping_countries[143]}", "${json.allowed_shipping_countries[144]}", "${json.allowed_shipping_countries[145]}", "${json.allowed_shipping_countries[146]}", "${json.allowed_shipping_countries[147]}", "${json.allowed_shipping_countries[148]}", "${json.allowed_shipping_countries[149]}", "${json.allowed_shipping_countries[150]}", "${json.allowed_shipping_countries[151]}", "${json.allowed_shipping_countries[152]}", "${json.allowed_shipping_countries[153]}", "${json.allowed_shipping_countries[154]}", "${json.allowed_shipping_countries[155]}", "${json.allowed_shipping_countries[156]}", "${json.allowed_shipping_countries[157]}", "${json.allowed_shipping_countries[158]}", "${json.allowed_shipping_countries[159]}", "${json.allowed_shipping_countries[160]}", "${json.allowed_shipping_countries[161]}", "${json.allowed_shipping_countries[162]}", "${json.allowed_shipping_countries[163]}", "${json.allowed_shipping_countries[164]}", "${json.allowed_shipping_countries[165]}", "${json.allowed_shipping_countries[166]}", "${json.allowed_shipping_countries[167]}", "${json.allowed_shipping_countries[168]}", "${json.allowed_shipping_countries[169]}", "${json.allowed_shipping_countries[170]}", "${json.allowed_shipping_countries[171]}", "${json.allowed_shipping_countries[172]}", "${json.allowed_shipping_countries[173]}", "${json.allowed_shipping_countries[174]}", "${json.allowed_shipping_countries[175]}", "${json.allowed_shipping_countries[176]}", "${json.allowed_shipping_countries[177]}", "${json.allowed_shipping_countries[178]}", "${json.allowed_shipping_countries[179]}", "${json.allowed_shipping_countries[180]}", "${json.allowed_shipping_countries[181]}", "${json.allowed_shipping_countries[182]}", "${json.allowed_shipping_countries[183]}", "${json.allowed_shipping_countries[184]}", "${json.allowed_shipping_countries[185]}", "${json.allowed_shipping_countries[186]}", "${json.allowed_shipping_countries[187]}", "${json.allowed_shipping_countries[188]}", "${json.allowed_shipping_countries[189]}", "${json.allowed_shipping_countries[190]}", "${json.allowed_shipping_countries[191]}", "${json.allowed_shipping_countries[192]}", "${json.allowed_shipping_countries[193]}", "${json.allowed_shipping_countries[194]}", "${json.allowed_shipping_countries[195]}", "${json.allowed_shipping_countries[196]}", "${json.allowed_shipping_countries[197]}", "${json.allowed_shipping_countries[198]}", "${json.allowed_shipping_countries[199]}", "${json.allowed_shipping_countries[200]}", "${json.allowed_shipping_countries[201]}", "${json.allowed_shipping_countries[202]}", "${json.allowed_shipping_countries[203]}", "${json.allowed_shipping_countries[204]}", "${json.allowed_shipping_countries[205]}", "${json.allowed_shipping_countries[206]}", "${json.allowed_shipping_countries[207]}", "${json.allowed_shipping_countries[208]}", "${json.allowed_shipping_countries[209]}", "${json.allowed_shipping_countries[210]}"],
+ "analytics_user_id": "${json.analytics_user_id}",
"cart": {
"items": [
{
- "image_url": "${json.cart.items[0].image_url}",
- "name": "${json.cart.items[0].name}",
- "product_url": "${json.cart.items[0].product_url}",
- "quantity": "${json.cart.items[0].quantity}",
- "reference": "${json.cart.items[0].reference}",
- "tax_rate": "${json.cart.items[0].tax_rate}",
- "total_price_excluding_tax": "${json.cart.items[0].total_price_excluding_tax}",
- "total_price_including_tax": "${json.cart.items[0].total_price_including_tax}",
- "total_tax_amount": "${json.cart.items[0].total_tax_amount}",
- "type": "${json.cart.items[0].type}",
+ "image_url": "${json.cart.items[0].image_url}",
+ "name": "${json.cart.items[0].name}",
+ "product_url": "${json.cart.items[0].product_url}",
+ "quantity": "${json.cart.items[0].quantity}",
+ "reference": "${json.cart.items[0].reference}",
+ "tax_rate": "${json.cart.items[0].tax_rate}",
+ "total_price_excluding_tax": "${json.cart.items[0].total_price_excluding_tax}",
+ "total_price_including_tax": "${json.cart.items[0].total_price_including_tax}",
+ "total_tax_amount": "${json.cart.items[0].total_tax_amount}",
+ "type": "${json.cart.items[0].type}",
"unit_price": "${json.cart.items[0].unit_price}"
}
- ],
- "subtotal": "${json.cart.subtotal}",
- "total_discount_amount_excluding_tax": "${json.cart.total_discount_amount_excluding_tax}",
- "total_price_excluding_tax": "${json.cart.total_price_excluding_tax}",
- "total_price_including_tax": "${json.cart.total_price_including_tax}",
- "total_shipping_amount_excluding_tax": "${json.cart.total_shipping_amount_excluding_tax}",
- "total_store_credit": "${json.cart.total_store_credit}",
- "total_surcharge_amount_excluding_tax": "${json.cart.total_surcharge_amount_excluding_tax}",
+ ],
+ "subtotal": "${json.cart.subtotal}",
+ "total_discount_amount_excluding_tax": "${json.cart.total_discount_amount_excluding_tax}",
+ "total_price_excluding_tax": "${json.cart.total_price_excluding_tax}",
+ "total_price_including_tax": "${json.cart.total_price_including_tax}",
+ "total_shipping_amount_excluding_tax": "${json.cart.total_shipping_amount_excluding_tax}",
+ "total_store_credit": "${json.cart.total_store_credit}",
+ "total_surcharge_amount_excluding_tax": "${json.cart.total_surcharge_amount_excluding_tax}",
"total_tax_amount": "${json.cart.total_tax_amount}"
- },
- "correlation_id": "f6df29e7-f850-4c36-81fc-11def2f44b81",
+ },
+ "correlation_id": "f6df29e7-f850-4c36-81fc-11def2f44b81",
"merchant_urls": {
- "checkout": "${json.merchant_urls.checkout}",
- "confirmation": "${json.merchant_urls.confirmation}",
+ "checkout": "${json.merchant_urls.checkout}",
+ "confirmation": "${json.merchant_urls.confirmation}",
"terms": "${json.merchant_urls.terms}"
- },
+ },
"options": {
- "allow_separate_shipping_address": "${json.options.allow_separate_shipping_address}",
- "allowed_customer_types": ["${json.options.allowed_customer_types[0]}"],
- "date_of_birth_mandatory": "${json.options.date_of_birth_mandatory}",
- "national_identification_number_mandatory": "${json.options.national_identification_number_mandatory}",
+ "allow_separate_shipping_address": "${json.options.allow_separate_shipping_address}",
+ "allowed_customer_types": ["${json.options.allowed_customer_types[0]}"],
+ "date_of_birth_mandatory": "${json.options.date_of_birth_mandatory}",
+ "national_identification_number_mandatory": "${json.options.national_identification_number_mandatory}",
"payment_selector_on_load": "${json.options.payment_selector_on_load}"
- },
+ },
"preview_payment_methods": [
{
"data": {
"days": "${json.preview_payment_methods[0].data.days}"
- },
- "id": "${json.preview_payment_methods[0].id}",
+ },
+ "id": "${json.preview_payment_methods[0].id}",
"type": "${json.preview_payment_methods[0].type}"
},
{
"data": {
- "allow_saved_card": "${json.preview_payment_methods[1].data.allow_saved_card}",
- "available_cards": ["${json.preview_payment_methods[1].data.available_cards[0]}", "${json.preview_payment_methods[1].data.available_cards[1]}"],
+ "allow_saved_card": "${json.preview_payment_methods[1].data.allow_saved_card}",
+ "available_cards": ["${json.preview_payment_methods[1].data.available_cards[0]}", "${json.preview_payment_methods[1].data.available_cards[1]}"],
"do_save_card": "${json.preview_payment_methods[1].data.do_save_card}"
- },
- "id": "${json.preview_payment_methods[1].id}",
+ },
+ "id": "${json.preview_payment_methods[1].id}",
"type": "${json.preview_payment_methods[1].type}"
}
- ],
- "required_fields": ["${json.required_fields[0]}", "${json.required_fields[1]}", "${json.required_fields[2]}", "${json.required_fields[3]}", "${json.required_fields[4]}", "${json.required_fields[5]}", "billing_address.care_of"],
+ ],
+ "required_fields": ["${json.required_fields[0]}", "${json.required_fields[1]}", "${json.required_fields[2]}", "${json.required_fields[3]}", "${json.required_fields[4]}", "${json.required_fields[5]}", "billing_address.care_of"],
"shared": {
"billing_address": {
- "care_of": "C/O Hakan Ostlund",
- "city": "AlingHelsingstadfors",
- "country": "${json.shared.billing_address.country}",
- "email": "${json.shared.billing_address.email}",
- "family_name": "Anglund",
- "given_name": "Eva InvoiceGreenNewSpec",
- "phone": "+46700012878",
- "postal_code": "${json.shared.billing_address.postal_code}",
+ "care_of": "C/O Hakan Ostlund",
+ "city": "AlingHelsingstadfors",
+ "country": "${json.shared.billing_address.country}",
+ "email": "${json.shared.billing_address.email}",
+ "family_name": "Anglund",
+ "given_name": "Eva InvoiceGreenNewSpec",
+ "phone": "+46700012878",
+ "postal_code": "${json.shared.billing_address.postal_code}",
"street_address": "Sveavägen 44, 11111 Stockholm, Sweden Eriks Gata gatan"
- },
+ },
"challenge": {
- "country": "${json.shared.challenge.country}",
- "email": "${json.shared.challenge.email}",
+ "country": "${json.shared.challenge.country}",
+ "email": "${json.shared.challenge.email}",
"postal_code": "${json.shared.challenge.postal_code}"
- },
- "currency": "${json.shared.currency}",
+ },
+ "currency": "${json.shared.currency}",
"customer": {
- "national_identification_number": "8910210312",
+ "national_identification_number": "8910210312",
"type": "${json.shared.customer.type}"
- },
+ },
"language": "${json.shared.language}"
- },
+ },
"status": {
- "prescreened": "${json.status.prescreened}",
+ "prescreened": "${json.status.prescreened}",
"require_terms_consent": "${json.status.require_terms_consent}"
}
}`,
@@ -291,90 +291,90 @@ export default function() {
// Request #5
res = http.post("https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25",
`{
- "allowed_billing_countries": ["${json.allowed_billing_countries[0]}", "${json.allowed_billing_countries[1]}", "${json.allowed_billing_countries[2]}", "${json.allowed_billing_countries[3]}", "${json.allowed_billing_countries[4]}", "${json.allowed_billing_countries[5]}", "${json.allowed_billing_countries[6]}", "${json.allowed_billing_countries[7]}", "${json.allowed_billing_countries[8]}", "${json.allowed_billing_countries[9]}", "${json.allowed_billing_countries[10]}", "${json.allowed_billing_countries[11]}", "${json.allowed_billing_countries[12]}", "${json.allowed_billing_countries[13]}", "${json.allowed_billing_countries[14]}", "${json.allowed_billing_countries[15]}", "${json.allowed_billing_countries[16]}", "${json.allowed_billing_countries[17]}", "${json.allowed_billing_countries[18]}", "${json.allowed_billing_countries[19]}", "${json.allowed_billing_countries[20]}", "${json.allowed_billing_countries[21]}", "${json.allowed_billing_countries[22]}", "${json.allowed_billing_countries[23]}", "${json.allowed_billing_countries[24]}", "${json.allowed_billing_countries[25]}", "${json.allowed_billing_countries[26]}", "${json.allowed_billing_countries[27]}", "${json.allowed_billing_countries[28]}", "${json.allowed_billing_countries[29]}", "${json.allowed_billing_countries[30]}", "${json.allowed_billing_countries[31]}", "${json.allowed_billing_countries[32]}", "${json.allowed_billing_countries[33]}", "${json.allowed_billing_countries[34]}", "${json.allowed_billing_countries[35]}", "${json.allowed_billing_countries[36]}", "${json.allowed_billing_countries[37]}", "${json.allowed_billing_countries[38]}", "${json.allowed_billing_countries[39]}", "${json.allowed_billing_countries[40]}", "${json.allowed_billing_countries[41]}", "${json.allowed_billing_countries[42]}", "${json.allowed_billing_countries[43]}", "${json.allowed_billing_countries[44]}", "${json.allowed_billing_countries[45]}", "${json.allowed_billing_countries[46]}", "${json.allowed_billing_countries[47]}", "${json.allowed_billing_countries[48]}", "${json.allowed_billing_countries[49]}", "${json.allowed_billing_countries[50]}", "${json.allowed_billing_countries[51]}", "${json.allowed_billing_countries[52]}", "${json.allowed_billing_countries[53]}", "${json.allowed_billing_countries[54]}", "${json.allowed_billing_countries[55]}", "${json.allowed_billing_countries[56]}", "${json.allowed_billing_countries[57]}", "${json.allowed_billing_countries[58]}", "${json.allowed_billing_countries[59]}", "${json.allowed_billing_countries[60]}", "${json.allowed_billing_countries[61]}", "${json.allowed_billing_countries[62]}", "${json.allowed_billing_countries[63]}", "${json.allowed_billing_countries[64]}", "${json.allowed_billing_countries[65]}", "${json.allowed_billing_countries[66]}", "${json.allowed_billing_countries[67]}", "${json.allowed_billing_countries[68]}", "${json.allowed_billing_countries[69]}", "${json.allowed_billing_countries[70]}", "${json.allowed_billing_countries[71]}", "${json.allowed_billing_countries[72]}", "${json.allowed_billing_countries[73]}", "${json.allowed_billing_countries[74]}", "${json.allowed_billing_countries[75]}", "${json.allowed_billing_countries[76]}", "${json.allowed_billing_countries[77]}", "${json.allowed_billing_countries[78]}", "${json.allowed_billing_countries[79]}", "${json.allowed_billing_countries[80]}", "${json.allowed_billing_countries[81]}", "${json.allowed_billing_countries[82]}", "${json.allowed_billing_countries[83]}", "${json.allowed_billing_countries[84]}", "${json.allowed_billing_countries[85]}", "${json.allowed_billing_countries[86]}", "${json.allowed_billing_countries[87]}", "${json.allowed_billing_countries[88]}", "${json.allowed_billing_countries[89]}", "${json.allowed_billing_countries[90]}", "${json.allowed_billing_countries[91]}", "${json.allowed_billing_countries[92]}", "${json.allowed_billing_countries[93]}", "${json.allowed_billing_countries[94]}", "${json.allowed_billing_countries[95]}", "${json.allowed_billing_countries[96]}", "${json.allowed_billing_countries[97]}", "${json.allowed_billing_countries[98]}", "${json.allowed_billing_countries[99]}", "${json.allowed_billing_countries[100]}", "${json.allowed_billing_countries[101]}", "${json.allowed_billing_countries[102]}", "${json.allowed_billing_countries[103]}", "${json.allowed_billing_countries[104]}", "${json.allowed_billing_countries[105]}", "${json.allowed_billing_countries[106]}", "${json.allowed_billing_countries[107]}", "${json.allowed_billing_countries[108]}", "${json.allowed_billing_countries[109]}", "${json.allowed_billing_countries[110]}", "${json.allowed_billing_countries[111]}", "${json.allowed_billing_countries[112]}", "${json.allowed_billing_countries[113]}", "${json.allowed_billing_countries[114]}", "${json.allowed_billing_countries[115]}", "${json.allowed_billing_countries[116]}", "${json.allowed_billing_countries[117]}", "${json.allowed_billing_countries[118]}", "${json.allowed_billing_countries[119]}", "${json.allowed_billing_countries[120]}", "${json.allowed_billing_countries[121]}", "${json.allowed_billing_countries[122]}", "${json.allowed_billing_countries[123]}", "${json.allowed_billing_countries[124]}", "${json.allowed_billing_countries[125]}", "${json.allowed_billing_countries[126]}", "${json.allowed_billing_countries[127]}", "${json.allowed_billing_countries[128]}", "${json.allowed_billing_countries[129]}", "${json.allowed_billing_countries[130]}", "${json.allowed_billing_countries[131]}", "${json.allowed_billing_countries[132]}", "${json.allowed_billing_countries[133]}", "${json.allowed_billing_countries[134]}", "${json.allowed_billing_countries[135]}", "${json.allowed_billing_countries[136]}", "${json.allowed_billing_countries[137]}", "${json.allowed_billing_countries[138]}", "${json.allowed_billing_countries[139]}", "${json.allowed_billing_countries[140]}", "${json.allowed_billing_countries[141]}", "${json.allowed_billing_countries[142]}", "${json.allowed_billing_countries[143]}", "${json.allowed_billing_countries[144]}", "${json.allowed_billing_countries[145]}", "${json.allowed_billing_countries[146]}", "${json.allowed_billing_countries[147]}", "${json.allowed_billing_countries[148]}", "${json.allowed_billing_countries[149]}", "${json.allowed_billing_countries[150]}", "${json.allowed_billing_countries[151]}", "${json.allowed_billing_countries[152]}", "${json.allowed_billing_countries[153]}", "${json.allowed_billing_countries[154]}", "${json.allowed_billing_countries[155]}", "${json.allowed_billing_countries[156]}", "${json.allowed_billing_countries[157]}", "${json.allowed_billing_countries[158]}", "${json.allowed_billing_countries[159]}", "${json.allowed_billing_countries[160]}", "${json.allowed_billing_countries[161]}", "${json.allowed_billing_countries[162]}", "${json.allowed_billing_countries[163]}", "${json.allowed_billing_countries[164]}", "${json.allowed_billing_countries[165]}", "${json.allowed_billing_countries[166]}", "${json.allowed_billing_countries[167]}", "${json.allowed_billing_countries[168]}", "${json.allowed_billing_countries[169]}", "${json.allowed_billing_countries[170]}", "${json.allowed_billing_countries[171]}", "${json.allowed_billing_countries[172]}", "${json.allowed_billing_countries[173]}", "${json.allowed_billing_countries[174]}", "${json.allowed_billing_countries[175]}", "${json.allowed_billing_countries[176]}", "${json.allowed_billing_countries[177]}", "${json.allowed_billing_countries[178]}", "${json.allowed_billing_countries[179]}", "${json.allowed_billing_countries[180]}", "${json.allowed_billing_countries[181]}", "${json.allowed_billing_countries[182]}", "${json.allowed_billing_countries[183]}", "${json.allowed_billing_countries[184]}", "${json.allowed_billing_countries[185]}", "${json.allowed_billing_countries[186]}", "${json.allowed_billing_countries[187]}", "${json.allowed_billing_countries[188]}", "${json.allowed_billing_countries[189]}", "${json.allowed_billing_countries[190]}", "${json.allowed_billing_countries[191]}", "${json.allowed_billing_countries[192]}", "${json.allowed_billing_countries[193]}", "${json.allowed_billing_countries[194]}", "${json.allowed_billing_countries[195]}", "${json.allowed_billing_countries[196]}", "${json.allowed_billing_countries[197]}", "${json.allowed_billing_countries[198]}", "${json.allowed_billing_countries[199]}", "${json.allowed_billing_countries[200]}", "${json.allowed_billing_countries[201]}", "${json.allowed_billing_countries[202]}", "${json.allowed_billing_countries[203]}", "${json.allowed_billing_countries[204]}", "${json.allowed_billing_countries[205]}", "${json.allowed_billing_countries[206]}", "${json.allowed_billing_countries[207]}", "${json.allowed_billing_countries[208]}", "${json.allowed_billing_countries[209]}", "${json.allowed_billing_countries[210]}"],
- "allowed_shipping_countries": ["${json.allowed_shipping_countries[0]}", "${json.allowed_shipping_countries[1]}", "${json.allowed_shipping_countries[2]}", "${json.allowed_shipping_countries[3]}", "${json.allowed_shipping_countries[4]}", "${json.allowed_shipping_countries[5]}", "${json.allowed_shipping_countries[6]}", "${json.allowed_shipping_countries[7]}", "${json.allowed_shipping_countries[8]}", "${json.allowed_shipping_countries[9]}", "${json.allowed_shipping_countries[10]}", "${json.allowed_shipping_countries[11]}", "${json.allowed_shipping_countries[12]}", "${json.allowed_shipping_countries[13]}", "${json.allowed_shipping_countries[14]}", "${json.allowed_shipping_countries[15]}", "${json.allowed_shipping_countries[16]}", "${json.allowed_shipping_countries[17]}", "${json.allowed_shipping_countries[18]}", "${json.allowed_shipping_countries[19]}", "${json.allowed_shipping_countries[20]}", "${json.allowed_shipping_countries[21]}", "${json.allowed_shipping_countries[22]}", "${json.allowed_shipping_countries[23]}", "${json.allowed_shipping_countries[24]}", "${json.allowed_shipping_countries[25]}", "${json.allowed_shipping_countries[26]}", "${json.allowed_shipping_countries[27]}", "${json.allowed_shipping_countries[28]}", "${json.allowed_shipping_countries[29]}", "${json.allowed_shipping_countries[30]}", "${json.allowed_shipping_countries[31]}", "${json.allowed_shipping_countries[32]}", "${json.allowed_shipping_countries[33]}", "${json.allowed_shipping_countries[34]}", "${json.allowed_shipping_countries[35]}", "${json.allowed_shipping_countries[36]}", "${json.allowed_shipping_countries[37]}", "${json.allowed_shipping_countries[38]}", "${json.allowed_shipping_countries[39]}", "${json.allowed_shipping_countries[40]}", "${json.allowed_shipping_countries[41]}", "${json.allowed_shipping_countries[42]}", "${json.allowed_shipping_countries[43]}", "${json.allowed_shipping_countries[44]}", "${json.allowed_shipping_countries[45]}", "${json.allowed_shipping_countries[46]}", "${json.allowed_shipping_countries[47]}", "${json.allowed_shipping_countries[48]}", "${json.allowed_shipping_countries[49]}", "${json.allowed_shipping_countries[50]}", "${json.allowed_shipping_countries[51]}", "${json.allowed_shipping_countries[52]}", "${json.allowed_shipping_countries[53]}", "${json.allowed_shipping_countries[54]}", "${json.allowed_shipping_countries[55]}", "${json.allowed_shipping_countries[56]}", "${json.allowed_shipping_countries[57]}", "${json.allowed_shipping_countries[58]}", "${json.allowed_shipping_countries[59]}", "${json.allowed_shipping_countries[60]}", "${json.allowed_shipping_countries[61]}", "${json.allowed_shipping_countries[62]}", "${json.allowed_shipping_countries[63]}", "${json.allowed_shipping_countries[64]}", "${json.allowed_shipping_countries[65]}", "${json.allowed_shipping_countries[66]}", "${json.allowed_shipping_countries[67]}", "${json.allowed_shipping_countries[68]}", "${json.allowed_shipping_countries[69]}", "${json.allowed_shipping_countries[70]}", "${json.allowed_shipping_countries[71]}", "${json.allowed_shipping_countries[72]}", "${json.allowed_shipping_countries[73]}", "${json.allowed_shipping_countries[74]}", "${json.allowed_shipping_countries[75]}", "${json.allowed_shipping_countries[76]}", "${json.allowed_shipping_countries[77]}", "${json.allowed_shipping_countries[78]}", "${json.allowed_shipping_countries[79]}", "${json.allowed_shipping_countries[80]}", "${json.allowed_shipping_countries[81]}", "${json.allowed_shipping_countries[82]}", "${json.allowed_shipping_countries[83]}", "${json.allowed_shipping_countries[84]}", "${json.allowed_shipping_countries[85]}", "${json.allowed_shipping_countries[86]}", "${json.allowed_shipping_countries[87]}", "${json.allowed_shipping_countries[88]}", "${json.allowed_shipping_countries[89]}", "${json.allowed_shipping_countries[90]}", "${json.allowed_shipping_countries[91]}", "${json.allowed_shipping_countries[92]}", "${json.allowed_shipping_countries[93]}", "${json.allowed_shipping_countries[94]}", "${json.allowed_shipping_countries[95]}", "${json.allowed_shipping_countries[96]}", "${json.allowed_shipping_countries[97]}", "${json.allowed_shipping_countries[98]}", "${json.allowed_shipping_countries[99]}", "${json.allowed_shipping_countries[100]}", "${json.allowed_shipping_countries[101]}", "${json.allowed_shipping_countries[102]}", "${json.allowed_shipping_countries[103]}", "${json.allowed_shipping_countries[104]}", "${json.allowed_shipping_countries[105]}", "${json.allowed_shipping_countries[106]}", "${json.allowed_shipping_countries[107]}", "${json.allowed_shipping_countries[108]}", "${json.allowed_shipping_countries[109]}", "${json.allowed_shipping_countries[110]}", "${json.allowed_shipping_countries[111]}", "${json.allowed_shipping_countries[112]}", "${json.allowed_shipping_countries[113]}", "${json.allowed_shipping_countries[114]}", "${json.allowed_shipping_countries[115]}", "${json.allowed_shipping_countries[116]}", "${json.allowed_shipping_countries[117]}", "${json.allowed_shipping_countries[118]}", "${json.allowed_shipping_countries[119]}", "${json.allowed_shipping_countries[120]}", "${json.allowed_shipping_countries[121]}", "${json.allowed_shipping_countries[122]}", "${json.allowed_shipping_countries[123]}", "${json.allowed_shipping_countries[124]}", "${json.allowed_shipping_countries[125]}", "${json.allowed_shipping_countries[126]}", "${json.allowed_shipping_countries[127]}", "${json.allowed_shipping_countries[128]}", "${json.allowed_shipping_countries[129]}", "${json.allowed_shipping_countries[130]}", "${json.allowed_shipping_countries[131]}", "${json.allowed_shipping_countries[132]}", "${json.allowed_shipping_countries[133]}", "${json.allowed_shipping_countries[134]}", "${json.allowed_shipping_countries[135]}", "${json.allowed_shipping_countries[136]}", "${json.allowed_shipping_countries[137]}", "${json.allowed_shipping_countries[138]}", "${json.allowed_shipping_countries[139]}", "${json.allowed_shipping_countries[140]}", "${json.allowed_shipping_countries[141]}", "${json.allowed_shipping_countries[142]}", "${json.allowed_shipping_countries[143]}", "${json.allowed_shipping_countries[144]}", "${json.allowed_shipping_countries[145]}", "${json.allowed_shipping_countries[146]}", "${json.allowed_shipping_countries[147]}", "${json.allowed_shipping_countries[148]}", "${json.allowed_shipping_countries[149]}", "${json.allowed_shipping_countries[150]}", "${json.allowed_shipping_countries[151]}", "${json.allowed_shipping_countries[152]}", "${json.allowed_shipping_countries[153]}", "${json.allowed_shipping_countries[154]}", "${json.allowed_shipping_countries[155]}", "${json.allowed_shipping_countries[156]}", "${json.allowed_shipping_countries[157]}", "${json.allowed_shipping_countries[158]}", "${json.allowed_shipping_countries[159]}", "${json.allowed_shipping_countries[160]}", "${json.allowed_shipping_countries[161]}", "${json.allowed_shipping_countries[162]}", "${json.allowed_shipping_countries[163]}", "${json.allowed_shipping_countries[164]}", "${json.allowed_shipping_countries[165]}", "${json.allowed_shipping_countries[166]}", "${json.allowed_shipping_countries[167]}", "${json.allowed_shipping_countries[168]}", "${json.allowed_shipping_countries[169]}", "${json.allowed_shipping_countries[170]}", "${json.allowed_shipping_countries[171]}", "${json.allowed_shipping_countries[172]}", "${json.allowed_shipping_countries[173]}", "${json.allowed_shipping_countries[174]}", "${json.allowed_shipping_countries[175]}", "${json.allowed_shipping_countries[176]}", "${json.allowed_shipping_countries[177]}", "${json.allowed_shipping_countries[178]}", "${json.allowed_shipping_countries[179]}", "${json.allowed_shipping_countries[180]}", "${json.allowed_shipping_countries[181]}", "${json.allowed_shipping_countries[182]}", "${json.allowed_shipping_countries[183]}", "${json.allowed_shipping_countries[184]}", "${json.allowed_shipping_countries[185]}", "${json.allowed_shipping_countries[186]}", "${json.allowed_shipping_countries[187]}", "${json.allowed_shipping_countries[188]}", "${json.allowed_shipping_countries[189]}", "${json.allowed_shipping_countries[190]}", "${json.allowed_shipping_countries[191]}", "${json.allowed_shipping_countries[192]}", "${json.allowed_shipping_countries[193]}", "${json.allowed_shipping_countries[194]}", "${json.allowed_shipping_countries[195]}", "${json.allowed_shipping_countries[196]}", "${json.allowed_shipping_countries[197]}", "${json.allowed_shipping_countries[198]}", "${json.allowed_shipping_countries[199]}", "${json.allowed_shipping_countries[200]}", "${json.allowed_shipping_countries[201]}", "${json.allowed_shipping_countries[202]}", "${json.allowed_shipping_countries[203]}", "${json.allowed_shipping_countries[204]}", "${json.allowed_shipping_countries[205]}", "${json.allowed_shipping_countries[206]}", "${json.allowed_shipping_countries[207]}", "${json.allowed_shipping_countries[208]}", "${json.allowed_shipping_countries[209]}", "${json.allowed_shipping_countries[210]}"],
- "analytics_user_id": "${json.analytics_user_id}",
+ "allowed_billing_countries": ["${json.allowed_billing_countries[0]}", "${json.allowed_billing_countries[1]}", "${json.allowed_billing_countries[2]}", "${json.allowed_billing_countries[3]}", "${json.allowed_billing_countries[4]}", "${json.allowed_billing_countries[5]}", "${json.allowed_billing_countries[6]}", "${json.allowed_billing_countries[7]}", "${json.allowed_billing_countries[8]}", "${json.allowed_billing_countries[9]}", "${json.allowed_billing_countries[10]}", "${json.allowed_billing_countries[11]}", "${json.allowed_billing_countries[12]}", "${json.allowed_billing_countries[13]}", "${json.allowed_billing_countries[14]}", "${json.allowed_billing_countries[15]}", "${json.allowed_billing_countries[16]}", "${json.allowed_billing_countries[17]}", "${json.allowed_billing_countries[18]}", "${json.allowed_billing_countries[19]}", "${json.allowed_billing_countries[20]}", "${json.allowed_billing_countries[21]}", "${json.allowed_billing_countries[22]}", "${json.allowed_billing_countries[23]}", "${json.allowed_billing_countries[24]}", "${json.allowed_billing_countries[25]}", "${json.allowed_billing_countries[26]}", "${json.allowed_billing_countries[27]}", "${json.allowed_billing_countries[28]}", "${json.allowed_billing_countries[29]}", "${json.allowed_billing_countries[30]}", "${json.allowed_billing_countries[31]}", "${json.allowed_billing_countries[32]}", "${json.allowed_billing_countries[33]}", "${json.allowed_billing_countries[34]}", "${json.allowed_billing_countries[35]}", "${json.allowed_billing_countries[36]}", "${json.allowed_billing_countries[37]}", "${json.allowed_billing_countries[38]}", "${json.allowed_billing_countries[39]}", "${json.allowed_billing_countries[40]}", "${json.allowed_billing_countries[41]}", "${json.allowed_billing_countries[42]}", "${json.allowed_billing_countries[43]}", "${json.allowed_billing_countries[44]}", "${json.allowed_billing_countries[45]}", "${json.allowed_billing_countries[46]}", "${json.allowed_billing_countries[47]}", "${json.allowed_billing_countries[48]}", "${json.allowed_billing_countries[49]}", "${json.allowed_billing_countries[50]}", "${json.allowed_billing_countries[51]}", "${json.allowed_billing_countries[52]}", "${json.allowed_billing_countries[53]}", "${json.allowed_billing_countries[54]}", "${json.allowed_billing_countries[55]}", "${json.allowed_billing_countries[56]}", "${json.allowed_billing_countries[57]}", "${json.allowed_billing_countries[58]}", "${json.allowed_billing_countries[59]}", "${json.allowed_billing_countries[60]}", "${json.allowed_billing_countries[61]}", "${json.allowed_billing_countries[62]}", "${json.allowed_billing_countries[63]}", "${json.allowed_billing_countries[64]}", "${json.allowed_billing_countries[65]}", "${json.allowed_billing_countries[66]}", "${json.allowed_billing_countries[67]}", "${json.allowed_billing_countries[68]}", "${json.allowed_billing_countries[69]}", "${json.allowed_billing_countries[70]}", "${json.allowed_billing_countries[71]}", "${json.allowed_billing_countries[72]}", "${json.allowed_billing_countries[73]}", "${json.allowed_billing_countries[74]}", "${json.allowed_billing_countries[75]}", "${json.allowed_billing_countries[76]}", "${json.allowed_billing_countries[77]}", "${json.allowed_billing_countries[78]}", "${json.allowed_billing_countries[79]}", "${json.allowed_billing_countries[80]}", "${json.allowed_billing_countries[81]}", "${json.allowed_billing_countries[82]}", "${json.allowed_billing_countries[83]}", "${json.allowed_billing_countries[84]}", "${json.allowed_billing_countries[85]}", "${json.allowed_billing_countries[86]}", "${json.allowed_billing_countries[87]}", "${json.allowed_billing_countries[88]}", "${json.allowed_billing_countries[89]}", "${json.allowed_billing_countries[90]}", "${json.allowed_billing_countries[91]}", "${json.allowed_billing_countries[92]}", "${json.allowed_billing_countries[93]}", "${json.allowed_billing_countries[94]}", "${json.allowed_billing_countries[95]}", "${json.allowed_billing_countries[96]}", "${json.allowed_billing_countries[97]}", "${json.allowed_billing_countries[98]}", "${json.allowed_billing_countries[99]}", "${json.allowed_billing_countries[100]}", "${json.allowed_billing_countries[101]}", "${json.allowed_billing_countries[102]}", "${json.allowed_billing_countries[103]}", "${json.allowed_billing_countries[104]}", "${json.allowed_billing_countries[105]}", "${json.allowed_billing_countries[106]}", "${json.allowed_billing_countries[107]}", "${json.allowed_billing_countries[108]}", "${json.allowed_billing_countries[109]}", "${json.allowed_billing_countries[110]}", "${json.allowed_billing_countries[111]}", "${json.allowed_billing_countries[112]}", "${json.allowed_billing_countries[113]}", "${json.allowed_billing_countries[114]}", "${json.allowed_billing_countries[115]}", "${json.allowed_billing_countries[116]}", "${json.allowed_billing_countries[117]}", "${json.allowed_billing_countries[118]}", "${json.allowed_billing_countries[119]}", "${json.allowed_billing_countries[120]}", "${json.allowed_billing_countries[121]}", "${json.allowed_billing_countries[122]}", "${json.allowed_billing_countries[123]}", "${json.allowed_billing_countries[124]}", "${json.allowed_billing_countries[125]}", "${json.allowed_billing_countries[126]}", "${json.allowed_billing_countries[127]}", "${json.allowed_billing_countries[128]}", "${json.allowed_billing_countries[129]}", "${json.allowed_billing_countries[130]}", "${json.allowed_billing_countries[131]}", "${json.allowed_billing_countries[132]}", "${json.allowed_billing_countries[133]}", "${json.allowed_billing_countries[134]}", "${json.allowed_billing_countries[135]}", "${json.allowed_billing_countries[136]}", "${json.allowed_billing_countries[137]}", "${json.allowed_billing_countries[138]}", "${json.allowed_billing_countries[139]}", "${json.allowed_billing_countries[140]}", "${json.allowed_billing_countries[141]}", "${json.allowed_billing_countries[142]}", "${json.allowed_billing_countries[143]}", "${json.allowed_billing_countries[144]}", "${json.allowed_billing_countries[145]}", "${json.allowed_billing_countries[146]}", "${json.allowed_billing_countries[147]}", "${json.allowed_billing_countries[148]}", "${json.allowed_billing_countries[149]}", "${json.allowed_billing_countries[150]}", "${json.allowed_billing_countries[151]}", "${json.allowed_billing_countries[152]}", "${json.allowed_billing_countries[153]}", "${json.allowed_billing_countries[154]}", "${json.allowed_billing_countries[155]}", "${json.allowed_billing_countries[156]}", "${json.allowed_billing_countries[157]}", "${json.allowed_billing_countries[158]}", "${json.allowed_billing_countries[159]}", "${json.allowed_billing_countries[160]}", "${json.allowed_billing_countries[161]}", "${json.allowed_billing_countries[162]}", "${json.allowed_billing_countries[163]}", "${json.allowed_billing_countries[164]}", "${json.allowed_billing_countries[165]}", "${json.allowed_billing_countries[166]}", "${json.allowed_billing_countries[167]}", "${json.allowed_billing_countries[168]}", "${json.allowed_billing_countries[169]}", "${json.allowed_billing_countries[170]}", "${json.allowed_billing_countries[171]}", "${json.allowed_billing_countries[172]}", "${json.allowed_billing_countries[173]}", "${json.allowed_billing_countries[174]}", "${json.allowed_billing_countries[175]}", "${json.allowed_billing_countries[176]}", "${json.allowed_billing_countries[177]}", "${json.allowed_billing_countries[178]}", "${json.allowed_billing_countries[179]}", "${json.allowed_billing_countries[180]}", "${json.allowed_billing_countries[181]}", "${json.allowed_billing_countries[182]}", "${json.allowed_billing_countries[183]}", "${json.allowed_billing_countries[184]}", "${json.allowed_billing_countries[185]}", "${json.allowed_billing_countries[186]}", "${json.allowed_billing_countries[187]}", "${json.allowed_billing_countries[188]}", "${json.allowed_billing_countries[189]}", "${json.allowed_billing_countries[190]}", "${json.allowed_billing_countries[191]}", "${json.allowed_billing_countries[192]}", "${json.allowed_billing_countries[193]}", "${json.allowed_billing_countries[194]}", "${json.allowed_billing_countries[195]}", "${json.allowed_billing_countries[196]}", "${json.allowed_billing_countries[197]}", "${json.allowed_billing_countries[198]}", "${json.allowed_billing_countries[199]}", "${json.allowed_billing_countries[200]}", "${json.allowed_billing_countries[201]}", "${json.allowed_billing_countries[202]}", "${json.allowed_billing_countries[203]}", "${json.allowed_billing_countries[204]}", "${json.allowed_billing_countries[205]}", "${json.allowed_billing_countries[206]}", "${json.allowed_billing_countries[207]}", "${json.allowed_billing_countries[208]}", "${json.allowed_billing_countries[209]}", "${json.allowed_billing_countries[210]}"],
+ "allowed_shipping_countries": ["${json.allowed_shipping_countries[0]}", "${json.allowed_shipping_countries[1]}", "${json.allowed_shipping_countries[2]}", "${json.allowed_shipping_countries[3]}", "${json.allowed_shipping_countries[4]}", "${json.allowed_shipping_countries[5]}", "${json.allowed_shipping_countries[6]}", "${json.allowed_shipping_countries[7]}", "${json.allowed_shipping_countries[8]}", "${json.allowed_shipping_countries[9]}", "${json.allowed_shipping_countries[10]}", "${json.allowed_shipping_countries[11]}", "${json.allowed_shipping_countries[12]}", "${json.allowed_shipping_countries[13]}", "${json.allowed_shipping_countries[14]}", "${json.allowed_shipping_countries[15]}", "${json.allowed_shipping_countries[16]}", "${json.allowed_shipping_countries[17]}", "${json.allowed_shipping_countries[18]}", "${json.allowed_shipping_countries[19]}", "${json.allowed_shipping_countries[20]}", "${json.allowed_shipping_countries[21]}", "${json.allowed_shipping_countries[22]}", "${json.allowed_shipping_countries[23]}", "${json.allowed_shipping_countries[24]}", "${json.allowed_shipping_countries[25]}", "${json.allowed_shipping_countries[26]}", "${json.allowed_shipping_countries[27]}", "${json.allowed_shipping_countries[28]}", "${json.allowed_shipping_countries[29]}", "${json.allowed_shipping_countries[30]}", "${json.allowed_shipping_countries[31]}", "${json.allowed_shipping_countries[32]}", "${json.allowed_shipping_countries[33]}", "${json.allowed_shipping_countries[34]}", "${json.allowed_shipping_countries[35]}", "${json.allowed_shipping_countries[36]}", "${json.allowed_shipping_countries[37]}", "${json.allowed_shipping_countries[38]}", "${json.allowed_shipping_countries[39]}", "${json.allowed_shipping_countries[40]}", "${json.allowed_shipping_countries[41]}", "${json.allowed_shipping_countries[42]}", "${json.allowed_shipping_countries[43]}", "${json.allowed_shipping_countries[44]}", "${json.allowed_shipping_countries[45]}", "${json.allowed_shipping_countries[46]}", "${json.allowed_shipping_countries[47]}", "${json.allowed_shipping_countries[48]}", "${json.allowed_shipping_countries[49]}", "${json.allowed_shipping_countries[50]}", "${json.allowed_shipping_countries[51]}", "${json.allowed_shipping_countries[52]}", "${json.allowed_shipping_countries[53]}", "${json.allowed_shipping_countries[54]}", "${json.allowed_shipping_countries[55]}", "${json.allowed_shipping_countries[56]}", "${json.allowed_shipping_countries[57]}", "${json.allowed_shipping_countries[58]}", "${json.allowed_shipping_countries[59]}", "${json.allowed_shipping_countries[60]}", "${json.allowed_shipping_countries[61]}", "${json.allowed_shipping_countries[62]}", "${json.allowed_shipping_countries[63]}", "${json.allowed_shipping_countries[64]}", "${json.allowed_shipping_countries[65]}", "${json.allowed_shipping_countries[66]}", "${json.allowed_shipping_countries[67]}", "${json.allowed_shipping_countries[68]}", "${json.allowed_shipping_countries[69]}", "${json.allowed_shipping_countries[70]}", "${json.allowed_shipping_countries[71]}", "${json.allowed_shipping_countries[72]}", "${json.allowed_shipping_countries[73]}", "${json.allowed_shipping_countries[74]}", "${json.allowed_shipping_countries[75]}", "${json.allowed_shipping_countries[76]}", "${json.allowed_shipping_countries[77]}", "${json.allowed_shipping_countries[78]}", "${json.allowed_shipping_countries[79]}", "${json.allowed_shipping_countries[80]}", "${json.allowed_shipping_countries[81]}", "${json.allowed_shipping_countries[82]}", "${json.allowed_shipping_countries[83]}", "${json.allowed_shipping_countries[84]}", "${json.allowed_shipping_countries[85]}", "${json.allowed_shipping_countries[86]}", "${json.allowed_shipping_countries[87]}", "${json.allowed_shipping_countries[88]}", "${json.allowed_shipping_countries[89]}", "${json.allowed_shipping_countries[90]}", "${json.allowed_shipping_countries[91]}", "${json.allowed_shipping_countries[92]}", "${json.allowed_shipping_countries[93]}", "${json.allowed_shipping_countries[94]}", "${json.allowed_shipping_countries[95]}", "${json.allowed_shipping_countries[96]}", "${json.allowed_shipping_countries[97]}", "${json.allowed_shipping_countries[98]}", "${json.allowed_shipping_countries[99]}", "${json.allowed_shipping_countries[100]}", "${json.allowed_shipping_countries[101]}", "${json.allowed_shipping_countries[102]}", "${json.allowed_shipping_countries[103]}", "${json.allowed_shipping_countries[104]}", "${json.allowed_shipping_countries[105]}", "${json.allowed_shipping_countries[106]}", "${json.allowed_shipping_countries[107]}", "${json.allowed_shipping_countries[108]}", "${json.allowed_shipping_countries[109]}", "${json.allowed_shipping_countries[110]}", "${json.allowed_shipping_countries[111]}", "${json.allowed_shipping_countries[112]}", "${json.allowed_shipping_countries[113]}", "${json.allowed_shipping_countries[114]}", "${json.allowed_shipping_countries[115]}", "${json.allowed_shipping_countries[116]}", "${json.allowed_shipping_countries[117]}", "${json.allowed_shipping_countries[118]}", "${json.allowed_shipping_countries[119]}", "${json.allowed_shipping_countries[120]}", "${json.allowed_shipping_countries[121]}", "${json.allowed_shipping_countries[122]}", "${json.allowed_shipping_countries[123]}", "${json.allowed_shipping_countries[124]}", "${json.allowed_shipping_countries[125]}", "${json.allowed_shipping_countries[126]}", "${json.allowed_shipping_countries[127]}", "${json.allowed_shipping_countries[128]}", "${json.allowed_shipping_countries[129]}", "${json.allowed_shipping_countries[130]}", "${json.allowed_shipping_countries[131]}", "${json.allowed_shipping_countries[132]}", "${json.allowed_shipping_countries[133]}", "${json.allowed_shipping_countries[134]}", "${json.allowed_shipping_countries[135]}", "${json.allowed_shipping_countries[136]}", "${json.allowed_shipping_countries[137]}", "${json.allowed_shipping_countries[138]}", "${json.allowed_shipping_countries[139]}", "${json.allowed_shipping_countries[140]}", "${json.allowed_shipping_countries[141]}", "${json.allowed_shipping_countries[142]}", "${json.allowed_shipping_countries[143]}", "${json.allowed_shipping_countries[144]}", "${json.allowed_shipping_countries[145]}", "${json.allowed_shipping_countries[146]}", "${json.allowed_shipping_countries[147]}", "${json.allowed_shipping_countries[148]}", "${json.allowed_shipping_countries[149]}", "${json.allowed_shipping_countries[150]}", "${json.allowed_shipping_countries[151]}", "${json.allowed_shipping_countries[152]}", "${json.allowed_shipping_countries[153]}", "${json.allowed_shipping_countries[154]}", "${json.allowed_shipping_countries[155]}", "${json.allowed_shipping_countries[156]}", "${json.allowed_shipping_countries[157]}", "${json.allowed_shipping_countries[158]}", "${json.allowed_shipping_countries[159]}", "${json.allowed_shipping_countries[160]}", "${json.allowed_shipping_countries[161]}", "${json.allowed_shipping_countries[162]}", "${json.allowed_shipping_countries[163]}", "${json.allowed_shipping_countries[164]}", "${json.allowed_shipping_countries[165]}", "${json.allowed_shipping_countries[166]}", "${json.allowed_shipping_countries[167]}", "${json.allowed_shipping_countries[168]}", "${json.allowed_shipping_countries[169]}", "${json.allowed_shipping_countries[170]}", "${json.allowed_shipping_countries[171]}", "${json.allowed_shipping_countries[172]}", "${json.allowed_shipping_countries[173]}", "${json.allowed_shipping_countries[174]}", "${json.allowed_shipping_countries[175]}", "${json.allowed_shipping_countries[176]}", "${json.allowed_shipping_countries[177]}", "${json.allowed_shipping_countries[178]}", "${json.allowed_shipping_countries[179]}", "${json.allowed_shipping_countries[180]}", "${json.allowed_shipping_countries[181]}", "${json.allowed_shipping_countries[182]}", "${json.allowed_shipping_countries[183]}", "${json.allowed_shipping_countries[184]}", "${json.allowed_shipping_countries[185]}", "${json.allowed_shipping_countries[186]}", "${json.allowed_shipping_countries[187]}", "${json.allowed_shipping_countries[188]}", "${json.allowed_shipping_countries[189]}", "${json.allowed_shipping_countries[190]}", "${json.allowed_shipping_countries[191]}", "${json.allowed_shipping_countries[192]}", "${json.allowed_shipping_countries[193]}", "${json.allowed_shipping_countries[194]}", "${json.allowed_shipping_countries[195]}", "${json.allowed_shipping_countries[196]}", "${json.allowed_shipping_countries[197]}", "${json.allowed_shipping_countries[198]}", "${json.allowed_shipping_countries[199]}", "${json.allowed_shipping_countries[200]}", "${json.allowed_shipping_countries[201]}", "${json.allowed_shipping_countries[202]}", "${json.allowed_shipping_countries[203]}", "${json.allowed_shipping_countries[204]}", "${json.allowed_shipping_countries[205]}", "${json.allowed_shipping_countries[206]}", "${json.allowed_shipping_countries[207]}", "${json.allowed_shipping_countries[208]}", "${json.allowed_shipping_countries[209]}", "${json.allowed_shipping_countries[210]}"],
+ "analytics_user_id": "${json.analytics_user_id}",
"available_payment_methods": [
{
"data": {
"days": "${json.available_payment_methods[0].data.days}"
- },
- "id": "${json.available_payment_methods[0].id}",
+ },
+ "id": "${json.available_payment_methods[0].id}",
"type": "${json.available_payment_methods[0].type}"
}
- ],
+ ],
"cart": {
"items": [
{
- "image_url": "${json.cart.items[0].image_url}",
- "name": "${json.cart.items[0].name}",
- "product_url": "${json.cart.items[0].product_url}",
- "quantity": "${json.cart.items[0].quantity}",
- "reference": "${json.cart.items[0].reference}",
- "tax_rate": "${json.cart.items[0].tax_rate}",
- "total_price_excluding_tax": "${json.cart.items[0].total_price_excluding_tax}",
- "total_price_including_tax": "${json.cart.items[0].total_price_including_tax}",
- "total_tax_amount": "${json.cart.items[0].total_tax_amount}",
- "type": "${json.cart.items[0].type}",
+ "image_url": "${json.cart.items[0].image_url}",
+ "name": "${json.cart.items[0].name}",
+ "product_url": "${json.cart.items[0].product_url}",
+ "quantity": "${json.cart.items[0].quantity}",
+ "reference": "${json.cart.items[0].reference}",
+ "tax_rate": "${json.cart.items[0].tax_rate}",
+ "total_price_excluding_tax": "${json.cart.items[0].total_price_excluding_tax}",
+ "total_price_including_tax": "${json.cart.items[0].total_price_including_tax}",
+ "total_tax_amount": "${json.cart.items[0].total_tax_amount}",
+ "type": "${json.cart.items[0].type}",
"unit_price": "${json.cart.items[0].unit_price}"
}
- ],
- "subtotal": "${json.cart.subtotal}",
- "total_discount_amount_excluding_tax": "${json.cart.total_discount_amount_excluding_tax}",
- "total_price_excluding_tax": "${json.cart.total_price_excluding_tax}",
- "total_price_including_tax": "${json.cart.total_price_including_tax}",
- "total_shipping_amount_excluding_tax": "${json.cart.total_shipping_amount_excluding_tax}",
- "total_store_credit": "${json.cart.total_store_credit}",
- "total_surcharge_amount_excluding_tax": "${json.cart.total_surcharge_amount_excluding_tax}",
+ ],
+ "subtotal": "${json.cart.subtotal}",
+ "total_discount_amount_excluding_tax": "${json.cart.total_discount_amount_excluding_tax}",
+ "total_price_excluding_tax": "${json.cart.total_price_excluding_tax}",
+ "total_price_including_tax": "${json.cart.total_price_including_tax}",
+ "total_shipping_amount_excluding_tax": "${json.cart.total_shipping_amount_excluding_tax}",
+ "total_store_credit": "${json.cart.total_store_credit}",
+ "total_surcharge_amount_excluding_tax": "${json.cart.total_surcharge_amount_excluding_tax}",
"total_tax_amount": "${json.cart.total_tax_amount}"
- },
- "correlation_id": "a6c51342-b107-4463-a2a0-b530f1bac03e",
+ },
+ "correlation_id": "a6c51342-b107-4463-a2a0-b530f1bac03e",
"merchant_urls": {
- "checkout": "${json.merchant_urls.checkout}",
- "confirmation": "${json.merchant_urls.confirmation}",
+ "checkout": "${json.merchant_urls.checkout}",
+ "confirmation": "${json.merchant_urls.confirmation}",
"terms": "${json.merchant_urls.terms}"
- },
+ },
"options": {
- "allow_separate_shipping_address": "${json.options.allow_separate_shipping_address}",
- "allowed_customer_types": ["${json.options.allowed_customer_types[0]}"],
- "date_of_birth_mandatory": "${json.options.date_of_birth_mandatory}",
- "national_identification_number_mandatory": "${json.options.national_identification_number_mandatory}",
+ "allow_separate_shipping_address": "${json.options.allow_separate_shipping_address}",
+ "allowed_customer_types": ["${json.options.allowed_customer_types[0]}"],
+ "date_of_birth_mandatory": "${json.options.date_of_birth_mandatory}",
+ "national_identification_number_mandatory": "${json.options.national_identification_number_mandatory}",
"payment_selector_on_load": "${json.options.payment_selector_on_load}"
- },
+ },
"shared": {
"billing_address": {
- "care_of": "${json.shared.billing_address.care_of}",
- "city": "${json.shared.billing_address.city}",
- "country": "${json.shared.billing_address.country}",
- "email": "${json.shared.billing_address.email}",
- "family_name": "${json.shared.billing_address.family_name}",
- "given_name": "${json.shared.billing_address.given_name}",
- "phone": "${json.shared.billing_address.phone}",
- "postal_code": "${json.shared.billing_address.postal_code}",
- "street_address": "${json.shared.billing_address.street_address}",
+ "care_of": "${json.shared.billing_address.care_of}",
+ "city": "${json.shared.billing_address.city}",
+ "country": "${json.shared.billing_address.country}",
+ "email": "${json.shared.billing_address.email}",
+ "family_name": "${json.shared.billing_address.family_name}",
+ "given_name": "${json.shared.billing_address.given_name}",
+ "phone": "${json.shared.billing_address.phone}",
+ "postal_code": "${json.shared.billing_address.postal_code}",
+ "street_address": "${json.shared.billing_address.street_address}",
"street_address2": "${json.shared.billing_address.street_address2}"
- },
+ },
"challenge": {
- "country": "${json.shared.challenge.country}",
- "email": "${json.shared.challenge.email}",
+ "country": "${json.shared.challenge.country}",
+ "email": "${json.shared.challenge.email}",
"postal_code": "${json.shared.challenge.postal_code}"
- },
- "currency": "${json.shared.currency}",
+ },
+ "currency": "${json.shared.currency}",
"customer": {
- "national_identification_number": "${json.shared.customer.national_identification_number}",
+ "national_identification_number": "${json.shared.customer.national_identification_number}",
"type": "${json.shared.customer.type}"
- },
- "language": "${json.shared.language}",
+ },
+ "language": "${json.shared.language}",
"selected_payment_method": {
"data": {
"days": 14
- },
- "id": "-1",
+ },
+ "id": "-1",
"type": "invoice"
}
- },
+ },
"status": {
- "prescreened": "${json.status.prescreened}",
+ "prescreened": "${json.status.prescreened}",
"require_terms_consent": "${json.status.require_terms_consent}"
}
}`,
diff --git a/go.mod b/go.mod
index fbbd62b80a..2015bb86fa 100644
--- a/go.mod
+++ b/go.mod
@@ -13,8 +13,8 @@ require (
github.com/andybalholm/brotli v0.0.0-20190704151324-71eb68cc467c
github.com/andybalholm/cascadia v1.0.0 // indirect
github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb // indirect
- github.com/dlclark/regexp2 v1.2.1-0.20200807145002-74bac81f00cf // indirect
- github.com/dop251/goja v0.0.0-20200831102558-9af81ddcf0e1
+ github.com/dlclark/regexp2 v1.4.0 // indirect
+ github.com/dop251/goja v0.0.0-20201007100345-a8e472c705eb
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4
github.com/eapache/go-resiliency v1.1.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20160609142408-bb955e01b934 // indirect
@@ -24,7 +24,7 @@ require (
github.com/ghodss/yaml v1.0.0 // indirect
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
github.com/gin-gonic/gin v1.1.5-0.20170702092826-d459835d2b07 // indirect
- github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect
+ github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/golang/snappy v0.0.0-20170215233205-553a64147049 // indirect
github.com/google/go-cmp v0.5.1 // indirect
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f // indirect
@@ -60,9 +60,8 @@ require (
github.com/spf13/cobra v0.0.4-0.20180629152535-a114f312e075
github.com/spf13/pflag v1.0.1
github.com/stretchr/testify v1.2.2
- github.com/tidwall/gjson v1.1.3
- github.com/tidwall/match v1.0.0 // indirect
- github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51
+ github.com/tidwall/gjson v1.6.1
+ github.com/tidwall/pretty v1.0.2
github.com/ugorji/go v1.1.7 // indirect
github.com/urfave/negroni v0.3.1-0.20180130044549-22c5532ea862
github.com/valyala/bytebufferpool v1.0.0 // indirect
@@ -71,7 +70,7 @@ require (
github.com/zyedidia/highlight v0.0.0-20170330143449-201131ce5cf5
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7
- golang.org/x/text v0.3.2
+ golang.org/x/text v0.3.3
golang.org/x/time v0.0.0-20170927054726-6dc17368e09b
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
diff --git a/go.sum b/go.sum
index fd7b88abaf..6dbf50f675 100644
--- a/go.sum
+++ b/go.sum
@@ -20,10 +20,10 @@ github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb h1:tUf55Po0vzOendQ
github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb/go.mod h1:U0vRfAucUOohvdCxt5MWLF+TePIL0xbCkbKIiV8TQCE=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dlclark/regexp2 v1.2.1-0.20200807145002-74bac81f00cf h1:YzK4awHmRwVVWhdNd4WGZk5/slLv68nv094yqpqjlwQ=
-github.com/dlclark/regexp2 v1.2.1-0.20200807145002-74bac81f00cf/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
-github.com/dop251/goja v0.0.0-20200831102558-9af81ddcf0e1 h1:/nXYAXRvBtojzc2bKSC5/pdu47O70ExaZ3lGipQFleA=
-github.com/dop251/goja v0.0.0-20200831102558-9af81ddcf0e1/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
+github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
+github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/dop251/goja v0.0.0-20201007100345-a8e472c705eb h1:358PKppXCE79d1HvEQWYtc5Moihb1pURjNhPZkouSPM=
+github.com/dop251/goja v0.0.0-20201007100345-a8e472c705eb/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=
@@ -45,8 +45,8 @@ github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cou
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-gonic/gin v1.1.5-0.20170702092826-d459835d2b07 h1:Gm6bjW5SQ/sIib9Zcgyyw5chSE6SLcgVZIflI0qGI6s=
github.com/gin-gonic/gin v1.1.5-0.20170702092826-d459835d2b07/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
-github.com/go-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug=
-github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
+github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
+github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721 h1:KRMr9A3qfbVM7iV/WcLY/rL5LICqwMHLhwRXKu99fXw=
github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
github.com/golang/protobuf v1.0.0 h1:lsek0oXi8iFE9L+EXARyHIjU5rlWIhhTkjDz3vHhWWQ=
@@ -135,10 +135,16 @@ github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/tidwall/gjson v1.1.3 h1:u4mspaByxY+Qk4U1QYYVzGFI8qxN/3jtEV0ZDb2vRic=
github.com/tidwall/gjson v1.1.3/go.mod h1:c/nTNbUr0E0OrXEhq1pwa8iEgc2DOt4ZZqAt1HtCkPA=
+github.com/tidwall/gjson v1.6.1 h1:LRbvNuNuvAiISWg6gxLEFuCe72UKy5hDqhxW/8183ws=
+github.com/tidwall/gjson v1.6.1/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0=
github.com/tidwall/match v1.0.0 h1:Ym1EcFkp+UQ4ptxfWlW+iMdq5cPH5nEuGzdf/Pb7VmI=
github.com/tidwall/match v1.0.0/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
+github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
+github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51 h1:BP2bjP495BBPaBcS5rmqviTfrOkN5rO5ceKAMRZCRFc=
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
+github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/ugorji/go v0.0.0-20180112141927-9831f2c3ac10 h1:4zp+5ElNBLy5qmaDFrbVDolQSOtPmquw+W6EMNEpi+k=
github.com/ugorji/go v0.0.0-20180112141927-9831f2c3ac10/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/urfave/negroni v0.3.1-0.20180130044549-22c5532ea862 h1:o3gEt3MZ4RRJUzO8qtPd31kJYU3m/ga9re5xbjVFUvA=
diff --git a/js/compiler/compiler.go b/js/compiler/compiler.go
index 719ee33efb..f72de6a817 100644
--- a/js/compiler/compiler.go
+++ b/js/compiler/compiler.go
@@ -70,7 +70,7 @@ func (c *Compiler) Transform(src, filename string) (code string, srcmap *SourceM
return b.Transform(c.logger, src, filename)
}
-// Compile the program in the given CompatibilityMode, optionally running pre and post code.
+// Compile the program in the given CompatibilityMode, wrapping it between pre and post code
func (c *Compiler) Compile(src, filename, pre, post string,
strict bool, compatMode lib.CompatibilityMode) (*goja.Program, string, error) {
code := pre + src + post
@@ -81,7 +81,8 @@ func (c *Compiler) Compile(src, filename, pre, post string,
if err != nil {
return nil, code, err
}
- return c.Compile(code, filename, pre, post, strict, compatMode)
+ // the compatibility mode "decreases" here as we shouldn't transform twice
+ return c.Compile(code, filename, pre, post, strict, lib.CompatibilityModeBase)
}
return nil, code, err
}
diff --git a/js/compiler/compiler_test.go b/js/compiler/compiler_test.go
index 44a7cce49f..a4b53fe338 100644
--- a/js/compiler/compiler_test.go
+++ b/js/compiler/compiler_test.go
@@ -22,8 +22,10 @@ package compiler
import (
"strings"
"testing"
+ "time"
"github.com/dop251/goja"
+ "github.com/dop251/goja/parser"
"github.com/stretchr/testify/assert"
"github.com/loadimpact/k6/lib"
@@ -149,5 +151,27 @@ func TestCompile(t *testing.T) {
assert.Contains(t, err.Error(), `SyntaxError: script.js: Unexpected token (1:3)
> 1 | 1+(=>2)()`)
})
+
+ t.Run("Invalid for goja but not babel", func(t *testing.T) {
+ t.Skip("Find something else that breaks this as this was fixed in goja :(")
+ ch := make(chan struct{})
+ go func() {
+ defer close(ch)
+ // This is a string with U+2029 Paragraph separator in it
+ // the important part is that goja won't parse it but babel will transform it but still
+ // goja won't be able to parse the result it is actually "\"
+ _, _, err := c.Compile(string([]byte{0x22, 0x5c, 0xe2, 0x80, 0xa9, 0x22}), "script.js", "", "", true, lib.CompatibilityModeExtended)
+ assert.IsType(t, parser.ErrorList{}, err)
+ assert.Contains(t, err.Error(), ` Unexpected token ILLEGAL`)
+ }()
+
+ select {
+ case <-ch:
+ // everything is fine
+ case <-time.After(time.Second):
+ // it took too long
+ t.Fatal("takes too long")
+ }
+ })
})
}
diff --git a/js/modules/k6/http/request_test.go b/js/modules/k6/http/request_test.go
index 09e8a3019e..c6608bc5b5 100644
--- a/js/modules/k6/http/request_test.go
+++ b/js/modules/k6/http/request_test.go
@@ -1669,7 +1669,7 @@ func TestErrorCodes(t *testing.T) {
name: "Unroutable",
expectedErrorCode: 1101,
expectedErrorMsg: "lookup: no such host",
- script: `var res = http.request("GET", "http://sdafsgdhfjg/");`,
+ script: `var res = http.request("GET", "http://sdafsgdhfjg.com/");`,
},
{
@@ -1683,7 +1683,7 @@ func TestErrorCodes(t *testing.T) {
expectedErrorCode: 1101,
expectedErrorMsg: "lookup: no such host",
moreSamples: 1,
- script: `var res = http.request("GET", "HTTPBIN_URL/redirect-to?url=http://dafsgdhfjg/");`,
+ script: `var res = http.request("GET", "HTTPBIN_URL/redirect-to?url=http://dafsgdhfjg.com/");`,
},
{
name: "Non location redirect",
@@ -1701,7 +1701,7 @@ func TestErrorCodes(t *testing.T) {
name: "Missing protocol",
expectedErrorCode: 1000,
expectedErrorMsg: `unsupported protocol scheme ""`,
- script: `var res = http.request("GET", "dafsgdhfjg/");`,
+ script: `var res = http.request("GET", "dafsgdhfjg.com/");`,
},
{
name: "Too many redirects",
diff --git a/log/loki.go b/log/loki.go
index 2a64dda14f..bef35c31d0 100644
--- a/log/loki.go
+++ b/log/loki.go
@@ -43,83 +43,108 @@ type lokiHook struct {
limit int
msgMaxSize int
levels []logrus.Level
+ allowedLabels []string
pushPeriod time.Duration
client *http.Client
ctx context.Context
fallbackLogger logrus.FieldLogger
profile bool
+ droppedLabels map[string]string
+ droppedMsg string
+}
+
+func getDefaultLoki() *lokiHook {
+ return &lokiHook{
+ addr: "http://127.0.0.1:3100/loki/api/v1/push",
+ limit: 100,
+ levels: logrus.AllLevels,
+ pushPeriod: time.Second * 1,
+ msgMaxSize: 1024 * 1024, // 1mb
+ ch: make(chan *logrus.Entry, 1000),
+ allowedLabels: nil,
+ droppedMsg: "k6 dropped %d log messages because they were above the limit of %d messages / %s",
+ }
}
// LokiFromConfigLine returns a new logrus.Hook that pushes logrus.Entrys to loki and is configured
// through the provided line
//nolint:funlen
func LokiFromConfigLine(ctx context.Context, fallbackLogger logrus.FieldLogger, line string) (logrus.Hook, error) {
- h := &lokiHook{
- addr: "http://127.0.0.1:3100/loki/api/v1/push",
- limit: 100,
- levels: logrus.AllLevels,
- pushPeriod: time.Second * 1,
- ctx: ctx,
- msgMaxSize: 1024 * 1024, // 1mb
- ch: make(chan *logrus.Entry, 1000),
- fallbackLogger: fallbackLogger,
- }
- if line == "loki" {
- return h, nil
- }
+ h := getDefaultLoki()
- parts := strings.SplitN(line, "=", 2)
- if parts[0] != "loki" {
- return nil, fmt.Errorf("loki configuration should be in the form `loki=url-to-push` but is `%s`", line)
+ h.ctx = ctx
+ h.fallbackLogger = fallbackLogger
+
+ if line != "loki" {
+ parts := strings.SplitN(line, "=", 2)
+ if parts[0] != "loki" {
+ return nil, fmt.Errorf("loki configuration should be in the form `loki=url-to-push` but is `%s`", line)
+ }
+
+ err := h.parseArgs(line)
+ if err != nil {
+ return nil, err
+ }
}
- args := strings.Split(parts[1], ",")
- h.addr = args[0]
- // TODO use something better ... maybe
- // https://godoc.org/github.com/kubernetes/helm/pkg/strvals
- // atleast until https://github.com/loadimpact/k6/issues/926?
- if len(args) == 1 {
- return h, nil
+ h.droppedLabels = make(map[string]string, 2+len(h.labels))
+ h.droppedLabels["level"] = logrus.WarnLevel.String()
+ for _, params := range h.labels {
+ h.droppedLabels[params[0]] = params[1]
}
- for _, arg := range args[1:] {
- paramParts := strings.SplitN(arg, "=", 2)
+ h.droppedMsg = h.filterLabels(h.droppedLabels, h.droppedMsg)
- if len(paramParts) != 2 {
- return nil, fmt.Errorf("loki arguments should be in the form `address,key1=value1,key2=value2`, got %s", arg)
- }
+ h.client = &http.Client{Timeout: h.pushPeriod}
- key, value := paramParts[0], paramParts[1]
+ go h.loop()
+
+ return h, nil
+}
+
+func (h *lokiHook) parseArgs(line string) error {
+ tokens, err := tokenize(line)
+ if err != nil {
+ return err
+ }
+
+ for _, token := range tokens {
+ key := token.key
+ value := token.value
var err error
switch key {
+ case "loki":
+ h.addr = value
case "pushPeriod":
h.pushPeriod, err = time.ParseDuration(value)
if err != nil {
- return nil, fmt.Errorf("couldn't parse the loki pushPeriod %w", err)
+ return fmt.Errorf("couldn't parse the loki pushPeriod %w", err)
}
case "profile":
h.profile = true
case "limit":
h.limit, err = strconv.Atoi(value)
if err != nil {
- return nil, fmt.Errorf("couldn't parse the loki limit as a number %w", err)
+ return fmt.Errorf("couldn't parse the loki limit as a number %w", err)
}
if !(h.limit > 0) {
- return nil, fmt.Errorf("loki limit needs to be a positive number, is %d", h.limit)
+ return fmt.Errorf("loki limit needs to be a positive number, is %d", h.limit)
}
case "msgMaxSize":
h.msgMaxSize, err = strconv.Atoi(value)
if err != nil {
- return nil, fmt.Errorf("couldn't parse the loki msgMaxSize as a number %w", err)
+ return fmt.Errorf("couldn't parse the loki msgMaxSize as a number %w", err)
}
if !(h.msgMaxSize > 0) {
- return nil, fmt.Errorf("loki msgMaxSize needs to be a positive number, is %d", h.msgMaxSize)
+ return fmt.Errorf("loki msgMaxSize needs to be a positive number, is %d", h.msgMaxSize)
}
case "level":
h.levels, err = getLevels(value)
if err != nil {
- return nil, err
+ return err
}
+ case "allowedLabels":
+ h.allowedLabels = strings.Split(value, ",")
default:
if strings.HasPrefix(key, "label.") {
labelKey := strings.TrimPrefix(key, "label.")
@@ -128,15 +153,11 @@ func LokiFromConfigLine(ctx context.Context, fallbackLogger logrus.FieldLogger,
continue
}
- return nil, fmt.Errorf("unknown loki config key %s", key)
+ return fmt.Errorf("unknown loki config key %s", key)
}
}
- h.client = &http.Client{Timeout: h.pushPeriod}
-
- go h.loop()
-
- return h, nil
+ return nil
}
func getLevels(level string) ([]logrus.Level, error) {
@@ -176,8 +197,7 @@ func (h *lokiHook) loop() {
cutOff := <-ch
close(ch) // signal that more buffering can continue
- copy(oldLogs[len(oldLogs):len(oldLogs)+oldCount], msgsToPush[:oldCount])
- oldLogs = oldLogs[:len(oldLogs)+oldCount]
+ oldLogs = append(oldLogs, msgsToPush[:oldCount]...)
t := time.Now()
cutOffIndex := sortAndSplitMsgs(oldLogs, cutOff)
@@ -244,12 +264,13 @@ func (h *lokiHook) loop() {
labels[params[0]] = params[1]
}
labels["level"] = entry.Level.String()
+ msg := h.filterLabels(labels, entry.Message) // TODO we can do this while constructing
// have the cutoff here ?
// if we cutoff here we can cut somewhat on the backbuffers and optimize the inserting
// in/creating of the final Streams that we push
msgs[count] = tmpMsg{
labels: labels,
- msg: entry.Message,
+ msg: msg,
t: entry.Time.UnixNano(),
}
count++
@@ -269,6 +290,36 @@ func (h *lokiHook) loop() {
}
}
+func (h *lokiHook) filterLabels(labels map[string]string, msg string) string {
+ if h.allowedLabels == nil {
+ return msg
+ }
+ // TODO both can be reused as under load this will just generate a lot of *probably* fairly
+ // similar objects.
+ var b strings.Builder
+ keys := make([]string, 0, len(labels))
+ for key := range labels {
+ keys = append(keys, key)
+ }
+ sort.Strings(keys)
+ b.WriteString(msg)
+outer:
+ for _, key := range keys {
+ for _, label := range h.allowedLabels {
+ if label == key {
+ continue outer
+ }
+ }
+ b.WriteRune(' ')
+ b.WriteString(key)
+ b.WriteRune('=')
+ b.WriteString(labels[key])
+ delete(labels, key)
+ }
+
+ return b.String()
+}
+
func sortAndSplitMsgs(msgs []tmpMsg, cutOff int64) int {
if len(msgs) == 0 {
return 0
@@ -294,17 +345,10 @@ func (h *lokiHook) createPushMessage(msgs []tmpMsg, cutOffIndex, dropped int) *l
pushMsg.add(msg)
}
if dropped != 0 {
- labels := make(map[string]string, 2+len(h.labels))
- labels["level"] = logrus.WarnLevel.String()
- for _, params := range h.labels {
- labels[params[0]] = params[1]
- }
-
msg := tmpMsg{
- labels: labels,
- msg: fmt.Sprintf("k6 dropped %d log messages because they were above the limit of %d messages / %s",
- dropped, h.limit, h.pushPeriod),
- t: msgs[cutOffIndex-1].t,
+ labels: h.droppedLabels,
+ msg: fmt.Sprintf(h.droppedMsg, dropped, h.limit, h.pushPeriod),
+ t: msgs[cutOffIndex-1].t,
}
pushMsg.add(msg)
}
diff --git a/log/loki_test.go b/log/loki_test.go
index ff41dbf59b..63de3cb5a2 100644
--- a/log/loki_test.go
+++ b/log/loki_test.go
@@ -23,10 +23,12 @@ package log
import (
"context"
"encoding/json"
+ "fmt"
"testing"
"time"
"github.com/sirupsen/logrus"
+ "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -40,24 +42,29 @@ func TestSyslogFromConfigLine(t *testing.T) {
{
line: "loki", // default settings
res: lokiHook{
- ctx: context.Background(),
- addr: "http://127.0.0.1:3100/loki/api/v1/push",
- limit: 100,
- pushPeriod: time.Second * 1,
- levels: logrus.AllLevels,
- msgMaxSize: 1024 * 1024,
+ ctx: context.Background(),
+ addr: "http://127.0.0.1:3100/loki/api/v1/push",
+ limit: 100,
+ pushPeriod: time.Second * 1,
+ levels: logrus.AllLevels,
+ msgMaxSize: 1024 * 1024,
+ droppedLabels: map[string]string{"level": "warning"},
+ droppedMsg: "k6 dropped %d log messages because they were above the limit of %d messages / %s",
},
},
{
- line: "loki=somewhere:1233,label.something=else,label.foo=bar,limit=32,level=info,pushPeriod=5m32s,msgMaxSize=1231",
+ line: "loki=somewhere:1233,label.something=else,label.foo=bar,limit=32,level=info,allowedLabels=[something],pushPeriod=5m32s,msgMaxSize=1231",
res: lokiHook{
- ctx: context.Background(),
- addr: "somewhere:1233",
- limit: 32,
- pushPeriod: time.Minute*5 + time.Second*32,
- levels: logrus.AllLevels[:5],
- labels: [][2]string{{"something", "else"}, {"foo", "bar"}},
- msgMaxSize: 1231,
+ ctx: context.Background(),
+ addr: "somewhere:1233",
+ limit: 32,
+ pushPeriod: time.Minute*5 + time.Second*32,
+ levels: logrus.AllLevels[:5],
+ labels: [][2]string{{"something", "else"}, {"foo", "bar"}},
+ msgMaxSize: 1231,
+ allowedLabels: []string{"something"},
+ droppedLabels: map[string]string{"something": "else"},
+ droppedMsg: "k6 dropped %d log messages because they were above the limit of %d messages / %s foo=bar level=warning",
},
},
{
@@ -112,3 +119,46 @@ func TestLogEntryMarshal(t *testing.T) {
require.Equal(t, expected, s)
}
+
+func TestFilterLabels(t *testing.T) {
+ cases := []struct {
+ allowedLabels []string
+ labels map[string]string
+ expectedLabels map[string]string
+ msg string
+ result string
+ }{
+ {
+ allowedLabels: []string{"a", "b"},
+ labels: map[string]string{"a": "1", "b": "2", "d": "3", "c": "4", "e": "5"},
+ expectedLabels: map[string]string{"a": "1", "b": "2"},
+ msg: "some msg",
+ result: "some msg c=4 d=3 e=5",
+ },
+ {
+ allowedLabels: []string{"a", "b"},
+ labels: map[string]string{"d": "3", "c": "4", "e": "5"},
+ expectedLabels: map[string]string{},
+ msg: "some msg",
+ result: "some msg c=4 d=3 e=5",
+ },
+ {
+ allowedLabels: []string{"a", "b"},
+ labels: map[string]string{"a": "1", "d": "3", "c": "4", "e": "5"},
+ expectedLabels: map[string]string{"a": "1"},
+ msg: "some msg",
+ result: "some msg c=4 d=3 e=5",
+ },
+ }
+
+ for i, c := range cases {
+ c := c
+ t.Run(fmt.Sprint(i), func(t *testing.T) {
+ h := &lokiHook{}
+ h.allowedLabels = c.allowedLabels
+ result := h.filterLabels(c.labels, c.msg)
+ assert.Equal(t, c.result, result)
+ assert.Equal(t, c.expectedLabels, c.labels)
+ })
+ }
+}
diff --git a/log/tokenizer.go b/log/tokenizer.go
new file mode 100644
index 0000000000..a48786e392
--- /dev/null
+++ b/log/tokenizer.go
@@ -0,0 +1,100 @@
+package log
+
+import "fmt"
+
+type token struct {
+ key, value string
+ inside rune // shows whether it's inside a given collection, currently [ means it's an array
+}
+
+type tokenizer struct {
+ i int
+ s string
+ currentKey string
+}
+
+func (t *tokenizer) readKey() (string, error) {
+ start := t.i
+ for ; t.i < len(t.s); t.i++ {
+ if t.s[t.i] == '=' {
+ t.i++
+
+ return t.s[start : t.i-1], nil
+ }
+ if t.s[t.i] == ',' {
+ k := t.s[start:t.i]
+
+ return k, fmt.Errorf("key `%s` with no value", k)
+ }
+ }
+
+ s := t.s[start:]
+
+ return s, fmt.Errorf("key `%s` with no value", s)
+}
+
+func (t *tokenizer) readValue() string {
+ start := t.i
+ for ; t.i < len(t.s); t.i++ {
+ if t.s[t.i] == ',' {
+ t.i++
+
+ return t.s[start : t.i-1]
+ }
+ }
+
+ return t.s[start:]
+}
+
+func (t *tokenizer) readArray() (string, error) {
+ start := t.i
+ for ; t.i < len(t.s); t.i++ {
+ if t.s[t.i] == ']' {
+ if t.i+1 == len(t.s) || t.s[t.i+1] == ',' {
+ t.i += 2
+
+ return t.s[start : t.i-2], nil
+ }
+ t.i++
+
+ return t.s[start : t.i-1], fmt.Errorf("there was no ',' after an array with key '%s'", t.currentKey)
+ }
+ }
+
+ return t.s[start:], fmt.Errorf("array value for key `%s` didn't end", t.currentKey)
+}
+
+func tokenize(s string) ([]token, error) {
+ result := []token{}
+ t := &tokenizer{s: s}
+
+ var err error
+ var value string
+ for t.i < len(s) {
+ t.currentKey, err = t.readKey()
+ if err != nil {
+ return result, err
+ }
+ if t.s[t.i] == '[' {
+ t.i++
+ value, err = t.readArray()
+
+ result = append(result, token{
+ key: t.currentKey,
+ value: value,
+ inside: '[',
+ })
+ if err != nil {
+ return result, err
+ }
+ } else {
+ value = t.readValue()
+ result = append(result, token{
+ key: t.currentKey,
+ value: value,
+ })
+ }
+ }
+
+ return result, nil
+}
diff --git a/log/tokenizer_test.go b/log/tokenizer_test.go
new file mode 100644
index 0000000000..83fa22aca9
--- /dev/null
+++ b/log/tokenizer_test.go
@@ -0,0 +1,44 @@
+package log
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestTokenizer(t *testing.T) {
+ tokens, err := tokenize("loki=something,s.e=2231,s=12,12=3,a=[1,2,3],b=[1],s=c")
+ assert.Equal(t, []token{
+ {
+ key: "loki",
+ value: "something",
+ },
+ {
+ key: "s.e",
+ value: "2231",
+ },
+ {
+ key: "s",
+ value: "12",
+ },
+ {
+ key: "12",
+ value: "3",
+ },
+ {
+ key: "a",
+ value: "1,2,3",
+ inside: '[',
+ },
+ {
+ key: "b",
+ value: "1",
+ inside: '[',
+ },
+ {
+ key: "s",
+ value: "c",
+ },
+ }, tokens)
+ assert.NoError(t, err)
+}
diff --git a/packaging/deb.json b/packaging/deb.json
index 5164c9bf94..93df0b5658 100644
--- a/packaging/deb.json
+++ b/packaging/deb.json
@@ -15,9 +15,9 @@
"copyrights": [
{
"files": "*",
- "copyright": "2018 Load Impact AB",
+ "copyright": "2020 Load Impact AB",
"license": "AGPL-3.0",
"file": "LICENSE"
}
]
- }
\ No newline at end of file
+ }
diff --git a/vendor/github.com/dlclark/regexp2/README.md b/vendor/github.com/dlclark/regexp2/README.md
index ec7b5abed4..4e4abb4c6f 100644
--- a/vendor/github.com/dlclark/regexp2/README.md
+++ b/vendor/github.com/dlclark/regexp2/README.md
@@ -43,8 +43,8 @@ The __last__ capture is embedded in each group, so `g.String()` will return the
| Category | regexp | regexp2 |
| --- | --- | --- |
| Catastrophic backtracking possible | no, constant execution time guarantees | yes, if your pattern is at risk you can use the `re.MatchTimeout` field |
-| Python-style capture groups `(Pre)` | yes | no |
-| .NET-style capture groups `(re)` or `('name're)` | no | yes |
+| Python-style capture groups `(?Pre)` | yes | no (yes in RE2 compat mode) |
+| .NET-style capture groups `(?re)` or `(?'name're)` | no | yes |
| comments `(?#comment)` | no | yes |
| branch numbering reset `(?\|a\|b)` | no | no |
| possessive match `(?>re)` | no | yes |
@@ -54,14 +54,15 @@ The __last__ capture is embedded in each group, so `g.String()` will return the
| negative lookbehind `(?re)`)
-
+* change singleline behavior for `$` to only match end of string (like RE2) (see [#24](https://github.com/dlclark/regexp2/issues/24))
+
```go
re := regexp2.MustCompile(`Your RE2-compatible pattern`, regexp2.RE2)
if isMatch, _ := re.MatchString(`Something to match`); isMatch {
diff --git a/vendor/github.com/dlclark/regexp2/runner.go b/vendor/github.com/dlclark/regexp2/runner.go
index 2d84a934b0..4d7f9b0611 100644
--- a/vendor/github.com/dlclark/regexp2/runner.go
+++ b/vendor/github.com/dlclark/regexp2/runner.go
@@ -566,9 +566,22 @@ func (r *runner) execute() error {
continue
case syntax.EndZ:
- if r.rightchars() > 1 || r.rightchars() == 1 && r.charAt(r.textPos()) != '\n' {
+ rchars := r.rightchars()
+ if rchars > 1 {
break
}
+ // RE2 and EcmaScript define $ as "asserts position at the end of the string"
+ // PCRE/.NET adds "or before the line terminator right at the end of the string (if any)"
+ if (r.re.options & (RE2 | ECMAScript)) != 0 {
+ // RE2/Ecmascript mode
+ if rchars > 0 {
+ break
+ }
+ } else if rchars == 1 && r.charAt(r.textPos()) != '\n' {
+ // "regular" mode
+ break
+ }
+
r.advance(0)
continue
@@ -938,8 +951,8 @@ func (r *runner) advance(i int) {
}
func (r *runner) goTo(newpos int) {
- // when branching backward, ensure storage
- if newpos < r.codepos {
+ // when branching backward or in place, ensure storage
+ if newpos <= r.codepos {
r.ensureStorage()
}
diff --git a/vendor/github.com/dlclark/regexp2/syntax/parser.go b/vendor/github.com/dlclark/regexp2/syntax/parser.go
index be88e2eede..da14f98e38 100644
--- a/vendor/github.com/dlclark/regexp2/syntax/parser.go
+++ b/vendor/github.com/dlclark/regexp2/syntax/parser.go
@@ -1648,7 +1648,7 @@ func (p *parser) scanOptions() {
}
// Scans \ code for escape codes that map to single unicode chars.
-func (p *parser) scanCharEscape() (rune, error) {
+func (p *parser) scanCharEscape() (r rune, err error) {
ch := p.moveRightGetChar()
@@ -1657,16 +1657,22 @@ func (p *parser) scanCharEscape() (rune, error) {
return p.scanOctal(), nil
}
+ pos := p.textpos()
+
switch ch {
case 'x':
// support for \x{HEX} syntax from Perl and PCRE
if p.charsRight() > 0 && p.rightChar(0) == '{' {
+ if p.useOptionE() {
+ return ch, nil
+ }
p.moveRight(1)
return p.scanHexUntilBrace()
+ } else {
+ r, err = p.scanHex(2)
}
- return p.scanHex(2)
case 'u':
- return p.scanHex(4)
+ r, err = p.scanHex(4)
case 'a':
return '\u0007', nil
case 'b':
@@ -1684,13 +1690,18 @@ func (p *parser) scanCharEscape() (rune, error) {
case 'v':
return '\u000B', nil
case 'c':
- return p.scanControl()
+ r, err = p.scanControl()
default:
if !p.useOptionE() && IsWordChar(ch) {
return 0, p.getErr(ErrUnrecognizedEscape, string(ch))
}
return ch, nil
}
+ if err != nil && p.useOptionE() {
+ p.textto(pos)
+ return ch, nil
+ }
+ return
}
// Grabs and converts an ascii control character
@@ -1807,7 +1818,7 @@ func (p *parser) scanOctal() rune {
//we know the first char is good because the caller had to check
i := 0
d := int(p.rightChar(0) - '0')
- for c > 0 && d <= 7 {
+ for c > 0 && d <= 7 && d >= 0 {
if i >= 0x20 && p.useOptionE() {
break
}
diff --git a/vendor/github.com/dop251/goja/README.md b/vendor/github.com/dop251/goja/README.md
index 2b9836816d..1a7efce2a3 100644
--- a/vendor/github.com/dop251/goja/README.md
+++ b/vendor/github.com/dop251/goja/README.md
@@ -21,6 +21,24 @@ Features
* Sourcemaps.
* Some ES6 functionality, still work in progress, see https://github.com/dop251/goja/milestone/1?closed=1
+Known incompatibilities and caveats
+-----------------------------------
+
+### WeakMap
+WeakMap maintains "hard" references to its values. This means if a value references a key in a WeakMap or a WeakMap
+itself, it will not be garbage-collected until the WeakMap becomes unreferenced. To illustrate this:
+
+```go
+var m = new WeakMap();
+var key = {};
+m.set(key, {key: key});
+// or m.set(key, key);
+key = undefined; // The value will NOT become garbage-collectable at this point
+m = undefined; // But it will at this point.
+```
+
+Note, this does not have any effect on the application logic, but causes a higher-than-expected memory usage.
+
FAQ
---
diff --git a/vendor/github.com/dop251/goja/builtin_regexp.go b/vendor/github.com/dop251/goja/builtin_regexp.go
index 3d3c0c35cf..2b0e4c4d08 100644
--- a/vendor/github.com/dop251/goja/builtin_regexp.go
+++ b/vendor/github.com/dop251/goja/builtin_regexp.go
@@ -852,21 +852,24 @@ func advanceStringIndex(s valueString, pos int, unicode bool) int {
func (r *Runtime) regexpproto_stdSplitter(call FunctionCall) Value {
rxObj := r.toObject(call.This)
- c := r.speciesConstructor(rxObj, r.global.RegExp)
- flags := nilSafe(rxObj.self.getStr("flags", nil)).toString()
- flagsStr := flags.String()
-
- // Add 'y' flag if missing
- if !strings.Contains(flagsStr, "y") {
- flags = newStringValue(flagsStr + "y")
- }
- splitter := c([]Value{rxObj, flags}, nil)
-
s := call.Argument(0).toString()
limitValue := call.Argument(1)
- search := r.checkStdRegexp(splitter)
- if search == nil {
- return r.regexpproto_stdSplitterGeneric(splitter, s, limitValue, strings.Contains(flagsStr, "u"))
+ var splitter *Object
+ search := r.checkStdRegexp(rxObj)
+ c := r.speciesConstructorObj(rxObj, r.global.RegExp)
+ if search == nil || c != r.global.RegExp {
+ flags := nilSafe(rxObj.self.getStr("flags", nil)).toString()
+ flagsStr := flags.String()
+
+ // Add 'y' flag if missing
+ if !strings.Contains(flagsStr, "y") {
+ flags = flags.concat(asciiString("y"))
+ }
+ splitter = r.toConstructor(c)([]Value{rxObj, flags}, nil)
+ search = r.checkStdRegexp(splitter)
+ if search == nil {
+ return r.regexpproto_stdSplitterGeneric(splitter, s, limitValue, strings.Contains(flagsStr, "u"))
+ }
}
limit := -1
diff --git a/vendor/github.com/dop251/goja/builtin_weakmap.go b/vendor/github.com/dop251/goja/builtin_weakmap.go
index 583576ed5c..bd614eec12 100644
--- a/vendor/github.com/dop251/goja/builtin_weakmap.go
+++ b/vendor/github.com/dop251/goja/builtin_weakmap.go
@@ -1,11 +1,6 @@
package goja
-import "sync"
-
type weakMap struct {
- // need to synchronise access to the data map because it may be accessed
- // from the finalizer goroutine
- sync.Mutex
data map[uint64]Value
}
@@ -26,57 +21,43 @@ func (wmo *weakMapObject) init() {
}
func (wm *weakMap) removeId(id uint64) {
- wm.Lock()
delete(wm.data, id)
- wm.Unlock()
}
func (wm *weakMap) set(key *Object, value Value) {
- refs := key.getWeakCollRefs()
- wm.Lock()
- wm.data[refs.id()] = value
- wm.Unlock()
- refs.add(wm)
+ ref := key.getWeakRef()
+ wm.data[ref.id] = value
+ key.runtime.addWeakKey(ref.id, wm)
}
func (wm *weakMap) get(key *Object) Value {
- refs := key.weakColls
- if refs == nil {
+ ref := key.weakRef
+ if ref == nil {
return nil
}
- wm.Lock()
- ret := wm.data[refs.id()]
- wm.Unlock()
+ ret := wm.data[ref.id]
return ret
}
func (wm *weakMap) remove(key *Object) bool {
- refs := key.weakColls
- if refs == nil {
+ ref := key.weakRef
+ if ref == nil {
return false
}
- id := refs.id()
- wm.Lock()
- _, exists := wm.data[id]
- if exists {
- delete(wm.data, id)
- }
- wm.Unlock()
+ _, exists := wm.data[ref.id]
if exists {
- refs.remove(wm)
+ delete(wm.data, ref.id)
+ key.runtime.removeWeakKey(ref.id, wm)
}
return exists
}
func (wm *weakMap) has(key *Object) bool {
- refs := key.weakColls
- if refs == nil {
+ ref := key.weakRef
+ if ref == nil {
return false
}
- id := refs.id()
- wm.Lock()
- _, exists := wm.data[id]
- wm.Unlock()
+ _, exists := wm.data[ref.id]
return exists
}
diff --git a/vendor/github.com/dop251/goja/builtin_weakset.go b/vendor/github.com/dop251/goja/builtin_weakset.go
index 91e72fd59e..fc61d40569 100644
--- a/vendor/github.com/dop251/goja/builtin_weakset.go
+++ b/vendor/github.com/dop251/goja/builtin_weakset.go
@@ -1,11 +1,6 @@
package goja
-import "sync"
-
type weakSet struct {
- // need to synchronise access to the data map because it may be accessed
- // from the finalizer goroutine
- sync.Mutex
data map[uint64]struct{}
}
@@ -26,43 +21,34 @@ func (ws *weakSetObject) init() {
}
func (ws *weakSet) removeId(id uint64) {
- ws.Lock()
delete(ws.data, id)
- ws.Unlock()
}
func (ws *weakSet) add(o *Object) {
- refs := o.getWeakCollRefs()
- ws.Lock()
- ws.data[refs.id()] = struct{}{}
- ws.Unlock()
- refs.add(ws)
+ ref := o.getWeakRef()
+ ws.data[ref.id] = struct{}{}
+ o.runtime.addWeakKey(ref.id, ws)
}
func (ws *weakSet) remove(o *Object) bool {
- if o.weakColls == nil {
+ ref := o.weakRef
+ if ref == nil {
return false
}
- id := o.weakColls.id()
- ws.Lock()
- _, exists := ws.data[id]
- if exists {
- delete(ws.data, id)
- }
- ws.Unlock()
+ _, exists := ws.data[ref.id]
if exists {
- o.weakColls.remove(ws)
+ delete(ws.data, ref.id)
+ o.runtime.removeWeakKey(ref.id, ws)
}
return exists
}
func (ws *weakSet) has(o *Object) bool {
- if o.weakColls == nil {
+ ref := o.weakRef
+ if ref == nil {
return false
}
- ws.Lock()
- _, exists := ws.data[o.weakColls.id()]
- ws.Unlock()
+ _, exists := ws.data[ref.id]
return exists
}
diff --git a/vendor/github.com/dop251/goja/object.go b/vendor/github.com/dop251/goja/object.go
index e48adc5719..4cefb55160 100644
--- a/vendor/github.com/dop251/goja/object.go
+++ b/vendor/github.com/dop251/goja/object.go
@@ -6,6 +6,7 @@ import (
"reflect"
"runtime"
"sort"
+ "sync"
"github.com/dop251/goja/unistring"
)
@@ -84,12 +85,27 @@ func (r *weakCollections) remove(c weakCollection) {
}
}
-func finalizeObjectWeakRefs(r *weakCollections) {
- id := r.id()
- for _, c := range r.colls {
- c.removeId(id)
- }
- r.colls = nil
+func finalizeObjectWeakRefs(r *objectWeakRef) {
+ r.tracker.add(r.id)
+}
+
+type weakRefTracker struct {
+ sync.Mutex
+ list []uint64
+}
+
+func (t *weakRefTracker) add(id uint64) {
+ t.Lock()
+ t.list = append(t.list, id)
+ t.Unlock()
+}
+
+// An object that gets finalized when the corresponding *Object is garbage-collected.
+// It must be ensured that neither the *Object, nor the *Runtime is reachable from this struct,
+// otherwise it will create a circular reference with a Finalizer which will make it not garbage-collectable.
+type objectWeakRef struct {
+ id uint64
+ tracker *weakRefTracker
}
type Object struct {
@@ -97,12 +113,7 @@ type Object struct {
runtime *Runtime
self objectImpl
- // Contains references to all weak collections that contain this Object.
- // weakColls has a finalizer that removes the Object's id from all weak collections.
- // The id is the weakColls pointer value converted to uintptr.
- // Note, cannot set the finalizer on the *Object itself because it's a part of a
- // reference cycle.
- weakColls *weakCollections
+ weakRef *objectWeakRef
}
type iterNextFunc func() (propIterItem, iterNextFunc)
@@ -1399,15 +1410,19 @@ func (o *Object) defineOwnProperty(n Value, desc PropertyDescriptor, throw bool)
}
}
-func (o *Object) getWeakCollRefs() *weakCollections {
- if o.weakColls == nil {
- o.weakColls = &weakCollections{
- objId: o.getId(),
+func (o *Object) getWeakRef() *objectWeakRef {
+ if o.weakRef == nil {
+ if o.runtime.weakRefTracker == nil {
+ o.runtime.weakRefTracker = &weakRefTracker{}
+ }
+ o.weakRef = &objectWeakRef{
+ id: o.getId(),
+ tracker: o.runtime.weakRefTracker,
}
- runtime.SetFinalizer(o.weakColls, finalizeObjectWeakRefs)
+ runtime.SetFinalizer(o.weakRef, finalizeObjectWeakRefs)
}
- return o.weakColls
+ return o.weakRef
}
func (o *Object) getId() uint64 {
diff --git a/vendor/github.com/dop251/goja/parser/expression.go b/vendor/github.com/dop251/goja/parser/expression.go
index ae418d06e9..afaf51218b 100644
--- a/vendor/github.com/dop251/goja/parser/expression.go
+++ b/vendor/github.com/dop251/goja/parser/expression.go
@@ -751,8 +751,6 @@ func (self *_parser) parseAssignmentExpression() ast.Expression {
operator = token.REMAINDER
case token.AND_ASSIGN:
operator = token.AND
- case token.AND_NOT_ASSIGN:
- operator = token.AND_NOT
case token.OR_ASSIGN:
operator = token.OR
case token.EXCLUSIVE_OR_ASSIGN:
diff --git a/vendor/github.com/dop251/goja/parser/lexer.go b/vendor/github.com/dop251/goja/parser/lexer.go
index da6e739c8e..4d0a810f08 100644
--- a/vendor/github.com/dop251/goja/parser/lexer.go
+++ b/vendor/github.com/dop251/goja/parser/lexer.go
@@ -354,12 +354,7 @@ func (self *_parser) scan() (tkn token.Token, literal string, parsedLiteral unis
tkn = token.STRICT_NOT_EQUAL
}
case '&':
- if self.chr == '^' {
- self.read()
- tkn = self.switch2(token.AND_NOT, token.AND_NOT_ASSIGN)
- } else {
- tkn = self.switch3(token.AND, token.AND_ASSIGN, '&', token.LOGICAL_AND)
- }
+ tkn = self.switch3(token.AND, token.AND_ASSIGN, '&', token.LOGICAL_AND)
case '|':
tkn = self.switch3(token.OR, token.OR_ASSIGN, '|', token.LOGICAL_OR)
case '~':
@@ -774,6 +769,9 @@ func parseStringLiteral1(literal string, length int, unicode bool) (unistring.St
var size int
value, size = utf8.DecodeRuneInString(str)
str = str[size:] // \ +
+ if value == '\u2028' || value == '\u2029' {
+ continue
+ }
} else {
str = str[2:] // \
switch chr {
diff --git a/vendor/github.com/dop251/goja/regexp.go b/vendor/github.com/dop251/goja/regexp.go
index 5303c99084..e8fd7d17a1 100644
--- a/vendor/github.com/dop251/goja/regexp.go
+++ b/vendor/github.com/dop251/goja/regexp.go
@@ -11,7 +11,17 @@ import (
"unicode/utf16"
)
-type regexp2Wrapper regexp2.Regexp
+type regexp2MatchCache struct {
+ target valueString
+ runes []rune
+ posMap []int
+}
+
+type regexp2Wrapper struct {
+ rx *regexp2.Regexp
+ cache *regexp2MatchCache
+}
+
type regexpWrapper regexp.Regexp
type positionMapItem struct {
@@ -20,8 +30,8 @@ type positionMapItem struct {
type positionMap []positionMapItem
func (m positionMap) get(src int) int {
- if src == 0 {
- return 0
+ if src <= 0 {
+ return src
}
res := sort.Search(len(m), func(n int) bool { return m[n].src >= src })
if res >= len(m) || m[res].src != src {
@@ -68,7 +78,7 @@ func compileRegexp2(src string, multiline, ignoreCase bool) (*regexp2Wrapper, er
return nil, fmt.Errorf("Invalid regular expression (regexp2): %s (%v)", src, err1)
}
- return (*regexp2Wrapper)(regexp2Pattern), nil
+ return ®exp2Wrapper{rx: regexp2Pattern}, nil
}
func (p *regexpPattern) createRegexp2() {
@@ -107,14 +117,14 @@ func buildUTF8PosMap(s valueString) (positionMap, string) {
func (p *regexpPattern) findSubmatchIndex(s valueString, start int) []int {
if p.regexpWrapper == nil {
- return p.regexp2Wrapper.findSubmatchIndex(s, start, p.unicode)
+ return p.regexp2Wrapper.findSubmatchIndex(s, start, p.unicode, p.global || p.sticky)
}
if start != 0 {
// Unfortunately Go's regexp library does not allow starting from an arbitrary position.
// If we just drop the first _start_ characters of the string the assertions (^, $, \b and \B) will not
// work correctly.
p.createRegexp2()
- return p.regexp2Wrapper.findSubmatchIndex(s, start, p.unicode)
+ return p.regexp2Wrapper.findSubmatchIndex(s, start, p.unicode, p.global || p.sticky)
}
return p.regexpWrapper.findSubmatchIndex(s, p.unicode)
}
@@ -128,7 +138,7 @@ func (p *regexpPattern) findAllSubmatchIndex(s valueString, start int, limit int
return p.regexpWrapper.findAllSubmatchIndex(s.String(), limit, sticky)
}
if limit == 1 {
- result := p.regexpWrapper.findSubmatchIndex(s, p.unicode)
+ result := p.regexpWrapper.findSubmatchIndexUnicode(s.(unicodeString), p.unicode)
if result == nil {
return nil
}
@@ -163,16 +173,41 @@ type regexpObject struct {
standard bool
}
-func (r *regexp2Wrapper) findSubmatchIndex(s valueString, start int, fullUnicode bool) (result []int) {
+func (r *regexp2Wrapper) findSubmatchIndex(s valueString, start int, fullUnicode, doCache bool) (result []int) {
if fullUnicode {
- return r.findSubmatchIndexUnicode(s, start)
+ return r.findSubmatchIndexUnicode(s, start, doCache)
+ }
+ return r.findSubmatchIndexUTF16(s, start, doCache)
+}
+
+func (r *regexp2Wrapper) findUTF16Cached(s valueString, start int, doCache bool) (match *regexp2.Match, runes []rune, err error) {
+ wrapped := r.rx
+ cache := r.cache
+ if cache != nil && cache.posMap == nil && cache.target.SameAs(s) {
+ runes = cache.runes
+ } else {
+ runes = s.utf16Runes()
+ cache = nil
+ }
+ match, err = wrapped.FindRunesMatchStartingAt(runes, start)
+ if doCache && match != nil && err == nil {
+ if cache == nil {
+ if r.cache == nil {
+ r.cache = new(regexp2MatchCache)
+ }
+ *r.cache = regexp2MatchCache{
+ target: s,
+ runes: runes,
+ }
+ }
+ } else {
+ r.cache = nil
}
- return r.findSubmatchIndexUTF16(s, start)
+ return
}
-func (r *regexp2Wrapper) findSubmatchIndexUTF16(s valueString, start int) (result []int) {
- wrapped := (*regexp2.Regexp)(r)
- match, err := wrapped.FindRunesMatchStartingAt(s.utf16Runes(), start)
+func (r *regexp2Wrapper) findSubmatchIndexUTF16(s valueString, start int, doCache bool) (result []int) {
+ match, _, err := r.findUTF16Cached(s, start, doCache)
if err != nil {
return
}
@@ -193,17 +228,55 @@ func (r *regexp2Wrapper) findSubmatchIndexUTF16(s valueString, start int) (resul
return
}
-func (r *regexp2Wrapper) findSubmatchIndexUnicode(s valueString, start int) (result []int) {
- wrapped := (*regexp2.Regexp)(r)
- posMap, runes, mappedStart := buildPosMap(&lenientUtf16Decoder{utf16Reader: s.utf16Reader(0)}, s.length(), start)
- match, err := wrapped.FindRunesMatchStartingAt(runes, mappedStart)
- if err != nil {
- return
+func (r *regexp2Wrapper) findUnicodeCached(s valueString, start int, doCache bool) (match *regexp2.Match, posMap []int, err error) {
+ var (
+ runes []rune
+ mappedStart int
+ splitPair bool
+ savedRune rune
+ )
+ wrapped := r.rx
+ cache := r.cache
+ if cache != nil && cache.posMap != nil && cache.target.SameAs(s) {
+ runes, posMap = cache.runes, cache.posMap
+ mappedStart, splitPair = posMapReverseLookup(posMap, start)
+ } else {
+ posMap, runes, mappedStart, splitPair = buildPosMap(&lenientUtf16Decoder{utf16Reader: s.utf16Reader(0)}, s.length(), start)
+ cache = nil
+ }
+ if splitPair {
+ // temporarily set the rune at mappedStart to the second code point of the pair
+ _, second := utf16.EncodeRune(runes[mappedStart])
+ savedRune, runes[mappedStart] = runes[mappedStart], second
+ }
+ match, err = wrapped.FindRunesMatchStartingAt(runes, mappedStart)
+ if doCache && match != nil && err == nil {
+ if splitPair {
+ runes[mappedStart] = savedRune
+ }
+ if cache == nil {
+ if r.cache == nil {
+ r.cache = new(regexp2MatchCache)
+ }
+ *r.cache = regexp2MatchCache{
+ target: s,
+ runes: runes,
+ posMap: posMap,
+ }
+ }
+ } else {
+ r.cache = nil
}
- if match == nil {
+ return
+}
+
+func (r *regexp2Wrapper) findSubmatchIndexUnicode(s valueString, start int, doCache bool) (result []int) {
+ match, posMap, err := r.findUnicodeCached(s, start, doCache)
+ if match == nil || err != nil {
return
}
+
groups := match.Groups()
result = make([]int, 0, len(groups)<<1)
@@ -218,10 +291,9 @@ func (r *regexp2Wrapper) findSubmatchIndexUnicode(s valueString, start int) (res
}
func (r *regexp2Wrapper) findAllSubmatchIndexUTF16(s valueString, start, limit int, sticky bool) [][]int {
- wrapped := (*regexp2.Regexp)(r)
- runes := s.utf16Runes()
- match, err := wrapped.FindRunesMatchStartingAt(runes, start)
- if err != nil {
+ wrapped := r.rx
+ match, runes, err := r.findUTF16Cached(s, start, false)
+ if match == nil || err != nil {
return nil
}
if limit < 0 {
@@ -263,7 +335,7 @@ func (r *regexp2Wrapper) findAllSubmatchIndexUTF16(s valueString, start, limit i
return results
}
-func buildPosMap(rd io.RuneReader, l, start int) (posMap []int, runes []rune, mappedStart int) {
+func buildPosMap(rd io.RuneReader, l, start int) (posMap []int, runes []rune, mappedStart int, splitPair bool) {
posMap = make([]int, 0, l+1)
curPos := 0
runes = make([]rune, 0, l)
@@ -277,8 +349,7 @@ func buildPosMap(rd io.RuneReader, l, start int) (posMap []int, runes []rune, ma
if curPos > start {
// start position splits a surrogate pair
mappedStart = len(runes) - 1
- _, second := utf16.EncodeRune(runes[mappedStart])
- runes[mappedStart] = second
+ splitPair = true
startFound = true
}
}
@@ -294,15 +365,21 @@ func buildPosMap(rd io.RuneReader, l, start int) (posMap []int, runes []rune, ma
return
}
+func posMapReverseLookup(posMap []int, pos int) (int, bool) {
+ mapped := sort.SearchInts(posMap, pos)
+ if mapped < len(posMap) && posMap[mapped] != pos {
+ return mapped - 1, true
+ }
+ return mapped, false
+}
+
func (r *regexp2Wrapper) findAllSubmatchIndexUnicode(s unicodeString, start, limit int, sticky bool) [][]int {
- wrapped := (*regexp2.Regexp)(r)
+ wrapped := r.rx
if limit < 0 {
limit = len(s) + 1
}
results := make([][]int, 0, limit)
- posMap, runes, mappedStart := buildPosMap(&lenientUtf16Decoder{utf16Reader: s.utf16Reader(0)}, s.length(), start)
-
- match, err := wrapped.FindRunesMatchStartingAt(runes, mappedStart)
+ match, posMap, err := r.findUnicodeCached(s, start, false)
if err != nil {
return nil
}
@@ -368,10 +445,26 @@ func (r *regexpWrapper) findAllSubmatchIndex(s string, limit int, sticky bool) (
return
}
-func (r *regexpWrapper) findSubmatchIndex(s valueString, fullUnicode bool) (result []int) {
+func (r *regexpWrapper) findSubmatchIndex(s valueString, fullUnicode bool) []int {
+ switch s := s.(type) {
+ case asciiString:
+ return r.findSubmatchIndexASCII(string(s))
+ case unicodeString:
+ return r.findSubmatchIndexUnicode(s, fullUnicode)
+ default:
+ panic("Unsupported string type")
+ }
+}
+
+func (r *regexpWrapper) findSubmatchIndexASCII(s string) []int {
+ wrapped := (*regexp.Regexp)(r)
+ return wrapped.FindStringSubmatchIndex(s)
+}
+
+func (r *regexpWrapper) findSubmatchIndexUnicode(s unicodeString, fullUnicode bool) (result []int) {
wrapped := (*regexp.Regexp)(r)
if fullUnicode {
- posMap, runes, _ := buildPosMap(&lenientUtf16Decoder{utf16Reader: s.utf16Reader(0)}, s.length(), 0)
+ posMap, runes, _, _ := buildPosMap(&lenientUtf16Decoder{utf16Reader: s.utf16Reader(0)}, s.length(), 0)
res := wrapped.FindReaderSubmatchIndex(&arrayRuneReader{runes: runes})
for i, item := range res {
res[i] = posMap[item]
diff --git a/vendor/github.com/dop251/goja/runtime.go b/vendor/github.com/dop251/goja/runtime.go
index e612f260ba..3ae19c671c 100644
--- a/vendor/github.com/dop251/goja/runtime.go
+++ b/vendor/github.com/dop251/goja/runtime.go
@@ -170,6 +170,16 @@ type Runtime struct {
vm *vm
hash *maphash.Hash
idSeq uint64
+
+ // Contains a list of ids of finalized weak keys so that the runtime could pick it up and remove from
+ // all weak collections using the weakKeys map. The runtime picks it up either when the topmost function
+ // returns (i.e. the callstack becomes empty) or every 10000 'ticks' (vm instructions).
+ // It is implemented this way to avoid circular references which at the time of writing (go 1.15) causes
+ // the whole structure to become not garbage-collectable.
+ weakRefTracker *weakRefTracker
+
+ // Contains a list of weak collections that contain the key with the id.
+ weakKeys map[uint64]*weakCollections
}
type StackFrame struct {
@@ -1195,6 +1205,7 @@ func (r *Runtime) RunProgram(p *Program) (result Value, err error) {
r.vm.clearStack()
} else {
r.vm.stack = nil
+ r.leave()
}
return
}
@@ -1966,7 +1977,11 @@ func AssertFunction(v Value) (Callable, bool) {
if ex != nil {
err = ex
}
- obj.runtime.vm.clearStack()
+ vm := obj.runtime.vm
+ vm.clearStack()
+ if len(vm.callStack) == 0 {
+ obj.runtime.leave()
+ }
return
}, true
}
@@ -2184,6 +2199,59 @@ func (r *Runtime) getHash() *maphash.Hash {
return r.hash
}
+func (r *Runtime) addWeakKey(id uint64, coll weakCollection) {
+ keys := r.weakKeys
+ if keys == nil {
+ keys = make(map[uint64]*weakCollections)
+ r.weakKeys = keys
+ }
+ colls := keys[id]
+ if colls == nil {
+ colls = &weakCollections{
+ objId: id,
+ }
+ keys[id] = colls
+ }
+ colls.add(coll)
+}
+
+func (r *Runtime) removeWeakKey(id uint64, coll weakCollection) {
+ keys := r.weakKeys
+ if colls := keys[id]; colls != nil {
+ colls.remove(coll)
+ if len(colls.colls) == 0 {
+ delete(keys, id)
+ }
+ }
+}
+
+// this gets inlined so a CALL is avoided on a critical path
+func (r *Runtime) removeDeadKeys() {
+ if r.weakRefTracker != nil {
+ r.doRemoveDeadKeys()
+ }
+}
+
+func (r *Runtime) doRemoveDeadKeys() {
+ r.weakRefTracker.Lock()
+ list := r.weakRefTracker.list
+ r.weakRefTracker.list = nil
+ r.weakRefTracker.Unlock()
+ for _, id := range list {
+ if colls := r.weakKeys[id]; colls != nil {
+ for _, coll := range colls.colls {
+ coll.removeId(id)
+ }
+ delete(r.weakKeys, id)
+ }
+ }
+}
+
+// called when the top level function returns (i.e. control is passed outside the Runtime).
+func (r *Runtime) leave() {
+ r.removeDeadKeys()
+}
+
func nilSafe(v Value) Value {
if v != nil {
return v
diff --git a/vendor/github.com/dop251/goja/string.go b/vendor/github.com/dop251/goja/string.go
index 1a35f442ca..6955054a2f 100644
--- a/vendor/github.com/dop251/goja/string.go
+++ b/vendor/github.com/dop251/goja/string.go
@@ -57,7 +57,6 @@ type valueString interface {
compareTo(valueString) int
reader(start int) io.RuneReader
utf16Reader(start int) io.RuneReader
- runes() []rune
utf16Runes() []rune
index(valueString, int) int
lastIndex(valueString, int) int
diff --git a/vendor/github.com/dop251/goja/string_ascii.go b/vendor/github.com/dop251/goja/string_ascii.go
index d997df9dc1..b265da33c5 100644
--- a/vendor/github.com/dop251/goja/string_ascii.go
+++ b/vendor/github.com/dop251/goja/string_ascii.go
@@ -40,7 +40,7 @@ func (s asciiString) utf16Reader(start int) io.RuneReader {
return s.reader(start)
}
-func (s asciiString) runes() []rune {
+func (s asciiString) utf16Runes() []rune {
runes := make([]rune, len(s))
for i := 0; i < len(s); i++ {
runes[i] = rune(s[i])
@@ -48,10 +48,6 @@ func (s asciiString) runes() []rune {
return runes
}
-func (s asciiString) utf16Runes() []rune {
- return s.runes()
-}
-
// ss must be trimmed
func strToInt(ss string) (int64, error) {
if ss == "" {
diff --git a/vendor/github.com/dop251/goja/string_unicode.go b/vendor/github.com/dop251/goja/string_unicode.go
index e976ca1c56..96b00ed01f 100644
--- a/vendor/github.com/dop251/goja/string_unicode.go
+++ b/vendor/github.com/dop251/goja/string_unicode.go
@@ -290,10 +290,6 @@ func (s unicodeString) utf16Reader(start int) io.RuneReader {
}
}
-func (s unicodeString) runes() []rune {
- return utf16.Decode(s[1:])
-}
-
func (s unicodeString) utf16Runes() []rune {
runes := make([]rune, len(s)-1)
for i, ch := range s[1:] {
diff --git a/vendor/github.com/dop251/goja/token/token.go b/vendor/github.com/dop251/goja/token/token.go
index 480b5cd656..c49794934a 100644
--- a/vendor/github.com/dop251/goja/token/token.go
+++ b/vendor/github.com/dop251/goja/token/token.go
@@ -40,7 +40,7 @@ func (tkn Token) precedence(in bool) int {
case EXCLUSIVE_OR:
return 4
- case AND, AND_ASSIGN, AND_NOT, AND_NOT_ASSIGN:
+ case AND, AND_ASSIGN:
return 5
case EQUAL,
diff --git a/vendor/github.com/dop251/goja/token/token_const.go b/vendor/github.com/dop251/goja/token/token_const.go
index 16976284ac..801fb604d5 100644
--- a/vendor/github.com/dop251/goja/token/token_const.go
+++ b/vendor/github.com/dop251/goja/token/token_const.go
@@ -26,7 +26,6 @@ const (
SHIFT_LEFT // <<
SHIFT_RIGHT // >>
UNSIGNED_SHIFT_RIGHT // >>>
- AND_NOT // &^
ADD_ASSIGN // +=
SUBTRACT_ASSIGN // -=
@@ -40,7 +39,6 @@ const (
SHIFT_LEFT_ASSIGN // <<=
SHIFT_RIGHT_ASSIGN // >>=
UNSIGNED_SHIFT_RIGHT_ASSIGN // >>>=
- AND_NOT_ASSIGN // &^=
LOGICAL_AND // &&
LOGICAL_OR // ||
@@ -133,7 +131,6 @@ var token2string = [...]string{
SHIFT_LEFT: "<<",
SHIFT_RIGHT: ">>",
UNSIGNED_SHIFT_RIGHT: ">>>",
- AND_NOT: "&^",
ADD_ASSIGN: "+=",
SUBTRACT_ASSIGN: "-=",
MULTIPLY_ASSIGN: "*=",
@@ -145,7 +142,6 @@ var token2string = [...]string{
SHIFT_LEFT_ASSIGN: "<<=",
SHIFT_RIGHT_ASSIGN: ">>=",
UNSIGNED_SHIFT_RIGHT_ASSIGN: ">>>=",
- AND_NOT_ASSIGN: "&^=",
LOGICAL_AND: "&&",
LOGICAL_OR: "||",
INCREMENT: "++",
diff --git a/vendor/github.com/dop251/goja/typedarrays.go b/vendor/github.com/dop251/goja/typedarrays.go
index 43cf355693..874eca2b5c 100644
--- a/vendor/github.com/dop251/goja/typedarrays.go
+++ b/vendor/github.com/dop251/goja/typedarrays.go
@@ -454,7 +454,7 @@ func (a *float64Array) typeMatch(v Value) bool {
func (a *typedArrayObject) _getIdx(idx int) Value {
a.viewedArrayBuf.ensureNotDetached()
- if idx < a.length {
+ if 0 <= idx && idx < a.length {
return a.typedArray.get(idx + a.offset)
}
return nil
diff --git a/vendor/github.com/dop251/goja/value.go b/vendor/github.com/dop251/goja/value.go
index 176d689b6e..140f508b9c 100644
--- a/vendor/github.com/dop251/goja/value.go
+++ b/vendor/github.com/dop251/goja/value.go
@@ -778,6 +778,12 @@ func (o *Object) Set(name string, value interface{}) error {
})
}
+func (o *Object) Delete(name string) error {
+ return tryFunc(func() {
+ o.self.deleteStr(unistring.NewFromString(name), true)
+ })
+}
+
// MarshalJSON returns JSON representation of the Object. It is equivalent to JSON.stringify(o).
// Note, this implements json.Marshaler so that json.Marshal() can be used without the need to Export().
func (o *Object) MarshalJSON() ([]byte, error) {
diff --git a/vendor/github.com/dop251/goja/vm.go b/vendor/github.com/dop251/goja/vm.go
index 91f6bc1f5c..26ed417963 100644
--- a/vendor/github.com/dop251/goja/vm.go
+++ b/vendor/github.com/dop251/goja/vm.go
@@ -308,6 +308,7 @@ func (vm *vm) run() {
ticks++
if ticks > 10000 {
runtime.Gosched()
+ vm.r.removeDeadKeys()
ticks = 0
}
}
diff --git a/vendor/github.com/go-sourcemap/sourcemap/consumer.go b/vendor/github.com/go-sourcemap/sourcemap/consumer.go
index 2a65085516..3b2f6e324d 100644
--- a/vendor/github.com/go-sourcemap/sourcemap/consumer.go
+++ b/vendor/github.com/go-sourcemap/sourcemap/consumer.go
@@ -9,13 +9,13 @@ import (
)
type sourceMap struct {
- Version int `json:"version"`
- File string `json:"file"`
- SourceRoot string `json:"sourceRoot"`
- Sources []string `json:"sources"`
- SourcesContent []string `json:"sourcesContent"`
- Names []json.Number `json:"names"`
- Mappings string `json:"mappings"`
+ Version int `json:"version"`
+ File string `json:"file"`
+ SourceRoot string `json:"sourceRoot"`
+ Sources []string `json:"sources"`
+ SourcesContent []string `json:"sourcesContent"`
+ Names []json.RawMessage `json:"names,string"`
+ Mappings string `json:"mappings"`
mappings []mapping
}
@@ -88,6 +88,26 @@ func (m *sourceMap) absSource(root *url.URL, source string) string {
return source
}
+func (m *sourceMap) name(idx int) string {
+ if idx >= len(m.Names) {
+ return ""
+ }
+
+ raw := m.Names[idx]
+ if len(raw) == 0 {
+ return ""
+ }
+
+ if raw[0] == '"' && raw[len(raw)-1] == '"' {
+ var str string
+ if err := json.Unmarshal(raw, &str); err == nil {
+ return str
+ }
+ }
+
+ return string(raw)
+}
+
type section struct {
Offset struct {
Line int `json:"line"`
@@ -191,7 +211,7 @@ func (c *Consumer) source(
source = m.Sources[match.sourcesInd]
}
if match.namesInd >= 0 {
- name = string(m.Names[match.namesInd])
+ name = m.name(int(match.namesInd))
}
line = int(match.sourceLine)
column = int(match.sourceColumn)
diff --git a/vendor/github.com/tidwall/gjson/README.md b/vendor/github.com/tidwall/gjson/README.md
index 70240d9927..4108deb378 100644
--- a/vendor/github.com/tidwall/gjson/README.md
+++ b/vendor/github.com/tidwall/gjson/README.md
@@ -55,6 +55,9 @@ Prichard
## Path Syntax
+Below is a quick overview of the path syntax, for more complete information please
+check out [GJSON Syntax](SYNTAX.md).
+
A path is a series of keys separated by a dot.
A key may contain special wildcard characters '\*' and '?'.
To access an array value use the index as the key.
@@ -68,9 +71,9 @@ The dot and wildcard characters can be escaped with '\\'.
"children": ["Sara","Alex","Jack"],
"fav.movie": "Deer Hunter",
"friends": [
- {"first": "Dale", "last": "Murphy", "age": 44},
- {"first": "Roger", "last": "Craig", "age": 68},
- {"first": "Jane", "last": "Murphy", "age": 47}
+ {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
+ {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
+ {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
]
}
```
@@ -87,45 +90,24 @@ The dot and wildcard characters can be escaped with '\\'.
"friends.1.last" >> "Craig"
```
-You can also query an array for the first match by using `#[...]`, or find all matches with `#[...]#`.
-Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` comparison operators and the simple pattern matching `%` operator.
+You can also query an array for the first match by using `#(...)`, or find all
+matches with `#(...)#`. Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=`
+comparison operators and the simple pattern matching `%` (like) and `!%`
+(not like) operators.
```
-friends.#[last=="Murphy"].first >> "Dale"
-friends.#[last=="Murphy"]#.first >> ["Dale","Jane"]
-friends.#[age>45]#.last >> ["Craig","Murphy"]
-friends.#[first%"D*"].last >> "Murphy"
+friends.#(last=="Murphy").first >> "Dale"
+friends.#(last=="Murphy")#.first >> ["Dale","Jane"]
+friends.#(age>45)#.last >> ["Craig","Murphy"]
+friends.#(first%"D*").last >> "Murphy"
+friends.#(first!%"D*").last >> "Craig"
+friends.#(nets.#(=="fb"))#.first >> ["Dale","Roger"]
```
-## JSON Lines
-
-There's support for [JSON Lines](http://jsonlines.org/) using the `..` prefix, which treats a multilined document as an array.
-
-For example:
-
-```
-{"name": "Gilbert", "age": 61}
-{"name": "Alexa", "age": 34}
-{"name": "May", "age": 57}
-{"name": "Deloise", "age": 44}
-```
-
-```
-..# >> 4
-..1 >> {"name": "Alexa", "age": 34}
-..3 >> {"name": "Deloise", "age": 44}
-..#.name >> ["Gilbert","Alexa","May","Deloise"]
-..#[name="May"].age >> 57
-```
-
-The `ForEachLines` function will iterate through JSON lines.
-
-```go
-gjson.ForEachLine(json, func(line gjson.Result) bool{
- println(line.String())
- return true
-})
-```
+*Please note that prior to v1.3.0, queries used the `#[...]` brackets. This was
+changed in v1.3.0 as to avoid confusion with the new
+[multipath](SYNTAX.md#multipaths) syntax. For backwards compatibility,
+`#[...]` will continue to work until the next major release.*
## Result Type
@@ -193,6 +175,118 @@ result.Int() int64 // -9223372036854775808 to 9223372036854775807
result.Uint() int64 // 0 to 18446744073709551615
```
+## Modifiers and path chaining
+
+New in version 1.2 is support for modifier functions and path chaining.
+
+A modifier is a path component that performs custom processing on the
+json.
+
+Multiple paths can be "chained" together using the pipe character.
+This is useful for getting results from a modified query.
+
+For example, using the built-in `@reverse` modifier on the above json document,
+we'll get `children` array and reverse the order:
+
+```
+"children|@reverse" >> ["Jack","Alex","Sara"]
+"children|@reverse|0" >> "Jack"
+```
+
+There are currently the following built-in modifiers:
+
+- `@reverse`: Reverse an array or the members of an object.
+- `@ugly`: Remove all whitespace from a json document.
+- `@pretty`: Make the json document more human readable.
+- `@this`: Returns the current element. It can be used to retrieve the root element.
+- `@valid`: Ensure the json document is valid.
+- `@flatten`: Flattens an array.
+- `@join`: Joins multiple objects into a single object.
+
+### Modifier arguments
+
+A modifier may accept an optional argument. The argument can be a valid JSON
+document or just characters.
+
+For example, the `@pretty` modifier takes a json object as its argument.
+
+```
+@pretty:{"sortKeys":true}
+```
+
+Which makes the json pretty and orders all of its keys.
+
+```json
+{
+ "age":37,
+ "children": ["Sara","Alex","Jack"],
+ "fav.movie": "Deer Hunter",
+ "friends": [
+ {"age": 44, "first": "Dale", "last": "Murphy"},
+ {"age": 68, "first": "Roger", "last": "Craig"},
+ {"age": 47, "first": "Jane", "last": "Murphy"}
+ ],
+ "name": {"first": "Tom", "last": "Anderson"}
+}
+```
+
+*The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`.
+Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.*
+
+### Custom modifiers
+
+You can also add custom modifiers.
+
+For example, here we create a modifier that makes the entire json document upper
+or lower case.
+
+```go
+gjson.AddModifier("case", func(json, arg string) string {
+ if arg == "upper" {
+ return strings.ToUpper(json)
+ }
+ if arg == "lower" {
+ return strings.ToLower(json)
+ }
+ return json
+})
+```
+
+```
+"children|@case:upper" >> ["SARA","ALEX","JACK"]
+"children|@case:lower|@reverse" >> ["jack","alex","sara"]
+```
+
+## JSON Lines
+
+There's support for [JSON Lines](http://jsonlines.org/) using the `..` prefix, which treats a multilined document as an array.
+
+For example:
+
+```
+{"name": "Gilbert", "age": 61}
+{"name": "Alexa", "age": 34}
+{"name": "May", "age": 57}
+{"name": "Deloise", "age": 44}
+```
+
+```
+..# >> 4
+..1 >> {"name": "Alexa", "age": 34}
+..3 >> {"name": "Deloise", "age": 44}
+..#.name >> ["Gilbert","Alexa","May","Deloise"]
+..#(name="May").age >> 57
+```
+
+The `ForEachLines` function will iterate through JSON lines.
+
+```go
+gjson.ForEachLine(json, func(line gjson.Result) bool{
+ println(line.String())
+ return true
+})
+```
+
## Get nested array values
Suppose you want all the last names from the following json:
@@ -226,7 +320,7 @@ for _, name := range result.Array() {
You can also query an object inside an array:
```go
-name := gjson.Get(json, `programmers.#[lastName="Hunter"].firstName`)
+name := gjson.Get(json, `programmers.#(lastName="Hunter").firstName`)
println(name.String()) // prints "Elliotte"
```
diff --git a/vendor/github.com/tidwall/gjson/SYNTAX.md b/vendor/github.com/tidwall/gjson/SYNTAX.md
new file mode 100644
index 0000000000..5ea0407f5a
--- /dev/null
+++ b/vendor/github.com/tidwall/gjson/SYNTAX.md
@@ -0,0 +1,277 @@
+# GJSON Path Syntax
+
+A GJSON Path is a text string syntax that describes a search pattern for quickly retreiving values from a JSON payload.
+
+This document is designed to explain the structure of a GJSON Path through examples.
+
+- [Path structure](#path-structure)
+- [Basic](#basic)
+- [Wildcards](#wildcards)
+- [Escape Character](#escape-character)
+- [Arrays](#arrays)
+- [Queries](#queries)
+- [Dot vs Pipe](#dot-vs-pipe)
+- [Modifiers](#modifiers)
+- [Multipaths](#multipaths)
+
+The definitive implemenation is [github.com/tidwall/gjson](https://github.com/tidwall/gjson).
+Use the [GJSON Playground](https://gjson.dev) to experiment with the syntax online.
+
+
+## Path structure
+
+A GJSON Path is intended to be easily expressed as a series of components seperated by a `.` character.
+
+Along with `.` character, there are a few more that have special meaning, including `|`, `#`, `@`, `\`, `*`, and `?`.
+
+## Example
+
+Given this JSON
+
+```json
+{
+ "name": {"first": "Tom", "last": "Anderson"},
+ "age":37,
+ "children": ["Sara","Alex","Jack"],
+ "fav.movie": "Deer Hunter",
+ "friends": [
+ {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
+ {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
+ {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
+ ]
+}
+```
+
+The following GJSON Paths evaluate to the accompanying values.
+
+### Basic
+
+In many cases you'll just want to retreive values by object name or array index.
+
+```go
+name.last "Anderson"
+name.first "Tom"
+age 37
+children ["Sara","Alex","Jack"]
+children.0 "Sara"
+children.1 "Alex"
+friends.1 {"first": "Roger", "last": "Craig", "age": 68}
+friends.1.first "Roger"
+```
+
+### Wildcards
+
+A key may contain the special wildcard characters `*` and `?`.
+The `*` will match on any zero+ characters, and `?` matches on any one character.
+
+```go
+child*.2 "Jack"
+c?ildren.0 "Sara"
+```
+
+### Escape character
+
+Special purpose characters, such as `.`, `*`, and `?` can be escaped with `\`.
+
+```go
+fav\.movie "Deer Hunter"
+```
+
+You'll also need to make sure that the `\` character is correctly escaped when hardcoding a path in source code.
+
+```go
+res := gjson.Get(json, "fav\\.movie") // must escape the slash
+res := gjson.Get(json, `fav\.movie`) // no need to escape the slash
+
+```
+
+### Arrays
+
+The `#` character allows for digging into JSON Arrays.
+
+To get the length of an array you'll just use the `#` all by itself.
+
+```go
+friends.# 3
+friends.#.age [44,68,47]
+```
+
+### Queries
+
+You can also query an array for the first match by using `#(...)`, or find all matches with `#(...)#`.
+Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` comparison operators,
+and the simple pattern matching `%` (like) and `!%` (not like) operators.
+
+```go
+friends.#(last=="Murphy").first "Dale"
+friends.#(last=="Murphy")#.first ["Dale","Jane"]
+friends.#(age>45)#.last ["Craig","Murphy"]
+friends.#(first%"D*").last "Murphy"
+friends.#(first!%"D*").last "Craig"
+```
+
+To query for a non-object value in an array, you can forgo the string to the right of the operator.
+
+```go
+children.#(!%"*a*") "Alex"
+children.#(%"*a*")# ["Sara","Jack"]
+```
+
+Nested queries are allowed.
+
+```go
+friends.#(nets.#(=="fb"))#.first >> ["Dale","Roger"]
+```
+
+*Please note that prior to v1.3.0, queries used the `#[...]` brackets. This was
+changed in v1.3.0 as to avoid confusion with the new [multipath](#multipaths)
+syntax. For backwards compatibility, `#[...]` will continue to work until the
+next major release.*
+
+### Dot vs Pipe
+
+The `.` is standard separator, but it's also possible to use a `|`.
+In most cases they both end up returning the same results.
+The cases where`|` differs from `.` is when it's used after the `#` for [Arrays](#arrays) and [Queries](#queries).
+
+Here are some examples
+
+```go
+friends.0.first "Dale"
+friends|0.first "Dale"
+friends.0|first "Dale"
+friends|0|first "Dale"
+friends|# 3
+friends.# 3
+friends.#(last="Murphy")# [{"first": "Dale", "last": "Murphy", "age": 44},{"first": "Jane", "last": "Murphy", "age": 47}]
+friends.#(last="Murphy")#.first ["Dale","Jane"]
+friends.#(last="Murphy")#|first
+friends.#(last="Murphy")#.0 []
+friends.#(last="Murphy")#|0 {"first": "Dale", "last": "Murphy", "age": 44}
+friends.#(last="Murphy")#.# []
+friends.#(last="Murphy")#|# 2
+```
+
+Let's break down a few of these.
+
+The path `friends.#(last="Murphy")#` all by itself results in
+
+```json
+[{"first": "Dale", "last": "Murphy", "age": 44},{"first": "Jane", "last": "Murphy", "age": 47}]
+```
+
+The `.first` suffix will process the `first` path on each array element *before* returning the results. Which becomes
+
+```json
+["Dale","Jane"]
+```
+
+But the `|first` suffix actually processes the `first` path *after* the previous result.
+Since the previous result is an array, not an object, it's not possible to process
+because `first` does not exist.
+
+Yet, `|0` suffix returns
+
+```json
+{"first": "Dale", "last": "Murphy", "age": 44}
+```
+
+Because `0` is the first index of the previous result.
+
+### Modifiers
+
+A modifier is a path component that performs custom processing on the JSON.
+
+For example, using the built-in `@reverse` modifier on the above JSON payload will reverse the `children` array:
+
+```go
+children.@reverse ["Jack","Alex","Sara"]
+children.@reverse.0 "Jack"
+```
+
+There are currently the following built-in modifiers:
+
+- `@reverse`: Reverse an array or the members of an object.
+- `@ugly`: Remove all whitespace from JSON.
+- `@pretty`: Make the JSON more human readable.
+- `@this`: Returns the current element. It can be used to retrieve the root element.
+- `@valid`: Ensure the json document is valid.
+- `@flatten`: Flattens an array.
+- `@join`: Joins multiple objects into a single object.
+
+#### Modifier arguments
+
+A modifier may accept an optional argument. The argument can be a valid JSON payload or just characters.
+
+For example, the `@pretty` modifier takes a json object as its argument.
+
+```
+@pretty:{"sortKeys":true}
+```
+
+Which makes the json pretty and orders all of its keys.
+
+```json
+{
+ "age":37,
+ "children": ["Sara","Alex","Jack"],
+ "fav.movie": "Deer Hunter",
+ "friends": [
+ {"age": 44, "first": "Dale", "last": "Murphy"},
+ {"age": 68, "first": "Roger", "last": "Craig"},
+ {"age": 47, "first": "Jane", "last": "Murphy"}
+ ],
+ "name": {"first": "Tom", "last": "Anderson"}
+}
+```
+
+*The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`.
+Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.*
+
+#### Custom modifiers
+
+You can also add custom modifiers.
+
+For example, here we create a modifier which makes the entire JSON payload upper or lower case.
+
+```go
+gjson.AddModifier("case", func(json, arg string) string {
+ if arg == "upper" {
+ return strings.ToUpper(json)
+ }
+ if arg == "lower" {
+ return strings.ToLower(json)
+ }
+ return json
+})
+"children.@case:upper" ["SARA","ALEX","JACK"]
+"children.@case:lower.@reverse" ["jack","alex","sara"]
+```
+
+### Multipaths
+
+Starting with v1.3.0, GJSON added the ability to join multiple paths together
+to form new documents. Wrapping comma-separated paths between `{...}` or
+`[...]` will result in a new array or object, respectively.
+
+For example, using the given multipath
+
+```
+{name.first,age,"the_murphys":friends.#(last="Murphy")#.first}
+```
+
+Here we selected the first name, age, and the first name for friends with the
+last name "Murphy".
+
+You'll notice that an optional key can be provided, in this case
+"the_murphys", to force assign a key to a value. Otherwise, the name of the
+actual field will be used, in this case "first". If a name cannot be
+determined, then "_" is used.
+
+This results in
+
+```
+{"first":"Tom","age":37,"the_murphys":["Dale","Jane"]}
+```
+
+
diff --git a/vendor/github.com/tidwall/gjson/gjson.go b/vendor/github.com/tidwall/gjson/gjson.go
index 74515ed507..0b6dcb0981 100644
--- a/vendor/github.com/tidwall/gjson/gjson.go
+++ b/vendor/github.com/tidwall/gjson/gjson.go
@@ -2,19 +2,17 @@
package gjson
import (
- "encoding/base64"
"encoding/json"
- "errors"
"reflect"
"strconv"
"strings"
- "sync"
- "sync/atomic"
"time"
"unicode/utf16"
"unicode/utf8"
+ "unsafe"
"github.com/tidwall/match"
+ "github.com/tidwall/pretty"
)
// Type is Result type
@@ -186,8 +184,9 @@ func (t Result) Time() time.Time {
}
// Array returns back an array of values.
-// If the result represents a non-existent value, then an empty array will be returned.
-// If the result is not a JSON array, the return value will be an array containing one result.
+// If the result represents a non-existent value, then an empty array will be
+// returned. If the result is not a JSON array, the return value will be an
+// array containing one result.
func (t Result) Array() []Result {
if t.Type == Null {
return []Result{}
@@ -210,10 +209,11 @@ func (t Result) IsArray() bool {
}
// ForEach iterates through values.
-// If the result represents a non-existent value, then no values will be iterated.
-// If the result is an Object, the iterator will pass the key and value of each item.
-// If the result is an Array, the iterator will only pass the value of each item.
-// If the result is not a JSON array or object, the iterator will pass back one value equal to the result.
+// If the result represents a non-existent value, then no values will be
+// iterated. If the result is an Object, the iterator will pass the key and
+// value of each item. If the result is an Array, the iterator will only pass
+// the value of each item. If the result is not a JSON array or object, the
+// iterator will pass back one value equal to the result.
func (t Result) ForEach(iterator func(key, value Result) bool) {
if !t.Exists() {
return
@@ -461,11 +461,13 @@ func ParseBytes(json []byte) Result {
}
func squash(json string) string {
- // expects that the lead character is a '[' or '{'
+ // expects that the lead character is a '[' or '{' or '(' or '"'
// squash the value, ignoring all nested arrays and objects.
- // the first '[' or '{' has already been read
- depth := 1
- for i := 1; i < len(json); i++ {
+ var i, depth int
+ if json[0] != '"' {
+ i, depth = 1, 1
+ }
+ for ; i < len(json); i++ {
if json[i] >= '"' && json[i] <= '}' {
switch json[i] {
case '"':
@@ -492,9 +494,12 @@ func squash(json string) string {
break
}
}
- case '{', '[':
+ if depth == 0 {
+ return json[:i+1]
+ }
+ case '{', '[', '(':
depth++
- case '}', ']':
+ case '}', ']', ')':
depth--
if depth == 0 {
return json[:i+1]
@@ -674,7 +679,8 @@ func parseNumber(json string, i int) (int, string) {
var s = i
i++
for ; i < len(json); i++ {
- if json[i] <= ' ' || json[i] == ',' || json[i] == ']' || json[i] == '}' {
+ if json[i] <= ' ' || json[i] == ',' || json[i] == ']' ||
+ json[i] == '}' {
return i, json[s:i]
}
}
@@ -695,6 +701,8 @@ func parseLiteral(json string, i int) (int, string) {
type arrayPathResult struct {
part string
path string
+ pipe string
+ piped bool
more bool
alogok bool
arrch bool
@@ -710,6 +718,12 @@ type arrayPathResult struct {
func parseArrayPath(path string) (r arrayPathResult) {
for i := 0; i < len(path); i++ {
+ if path[i] == '|' {
+ r.part = path[:i]
+ r.pipe = path[i+1:]
+ r.piped = true
+ return
+ }
if path[i] == '.' {
r.part = path[:i]
r.path = path[i+1:]
@@ -723,100 +737,122 @@ func parseArrayPath(path string) (r arrayPathResult) {
r.alogok = true
r.alogkey = path[2:]
r.path = path[:1]
- } else if path[1] == '[' {
- r.query.on = true
+ } else if path[1] == '[' || path[1] == '(' {
// query
- i += 2
- // whitespace
- for ; i < len(path); i++ {
- if path[i] > ' ' {
+ r.query.on = true
+ if true {
+ qpath, op, value, _, fi, ok := parseQuery(path[i:])
+ if !ok {
+ // bad query, end now
break
}
- }
- s := i
- for ; i < len(path); i++ {
- if path[i] <= ' ' ||
- path[i] == '!' ||
- path[i] == '=' ||
- path[i] == '<' ||
- path[i] == '>' ||
- path[i] == '%' ||
- path[i] == ']' {
- break
+ r.query.path = qpath
+ r.query.op = op
+ r.query.value = value
+ i = fi - 1
+ if i+1 < len(path) && path[i+1] == '#' {
+ r.query.all = true
}
- }
- r.query.path = path[s:i]
- // whitespace
- for ; i < len(path); i++ {
- if path[i] > ' ' {
- break
+ } else {
+ var end byte
+ if path[1] == '[' {
+ end = ']'
+ } else {
+ end = ')'
}
- }
- if i < len(path) {
- s = i
- if path[i] == '!' {
- if i < len(path)-1 && path[i+1] == '=' {
- i++
- }
- } else if path[i] == '<' || path[i] == '>' {
- if i < len(path)-1 && path[i+1] == '=' {
- i++
+ i += 2
+ // whitespace
+ for ; i < len(path); i++ {
+ if path[i] > ' ' {
+ break
}
- } else if path[i] == '=' {
- if i < len(path)-1 && path[i+1] == '=' {
- s++
- i++
+ }
+ s := i
+ for ; i < len(path); i++ {
+ if path[i] <= ' ' ||
+ path[i] == '!' ||
+ path[i] == '=' ||
+ path[i] == '<' ||
+ path[i] == '>' ||
+ path[i] == '%' ||
+ path[i] == end {
+ break
}
}
- i++
- r.query.op = path[s:i]
+ r.query.path = path[s:i]
// whitespace
for ; i < len(path); i++ {
if path[i] > ' ' {
break
}
}
- s = i
- for ; i < len(path); i++ {
- if path[i] == '"' {
- i++
- s2 := i
- for ; i < len(path); i++ {
- if path[i] > '\\' {
- continue
- }
- if path[i] == '"' {
- // look for an escaped slash
- if path[i-1] == '\\' {
- n := 0
- for j := i - 2; j > s2-1; j-- {
- if path[j] != '\\' {
- break
+ if i < len(path) {
+ s = i
+ if path[i] == '!' {
+ if i < len(path)-1 && (path[i+1] == '=' ||
+ path[i+1] == '%') {
+ i++
+ }
+ } else if path[i] == '<' || path[i] == '>' {
+ if i < len(path)-1 && path[i+1] == '=' {
+ i++
+ }
+ } else if path[i] == '=' {
+ if i < len(path)-1 && path[i+1] == '=' {
+ s++
+ i++
+ }
+ }
+ i++
+ r.query.op = path[s:i]
+ // whitespace
+ for ; i < len(path); i++ {
+ if path[i] > ' ' {
+ break
+ }
+ }
+ s = i
+ for ; i < len(path); i++ {
+ if path[i] == '"' {
+ i++
+ s2 := i
+ for ; i < len(path); i++ {
+ if path[i] > '\\' {
+ continue
+ }
+ if path[i] == '"' {
+ // look for an escaped slash
+ if path[i-1] == '\\' {
+ n := 0
+ for j := i - 2; j > s2-1; j-- {
+ if path[j] != '\\' {
+ break
+ }
+ n++
+ }
+ if n%2 == 0 {
+ continue
}
- n++
- }
- if n%2 == 0 {
- continue
}
+ break
}
- break
}
+ } else if path[i] == end {
+ if i+1 < len(path) && path[i+1] == '#' {
+ r.query.all = true
+ }
+ break
}
- } else if path[i] == ']' {
- if i+1 < len(path) && path[i+1] == '#' {
- r.query.all = true
- }
- break
}
+ if i > len(path) {
+ i = len(path)
+ }
+ v := path[s:i]
+ for len(v) > 0 && v[len(v)-1] <= ' ' {
+ v = v[:len(v)-1]
+ }
+ r.query.value = v
}
- if i > len(path) {
- i = len(path)
- }
- v := path[s:i]
- for len(v) > 0 && v[len(v)-1] <= ' ' {
- v = v[:len(v)-1]
- }
- r.query.value = v
}
}
}
@@ -828,19 +864,145 @@ func parseArrayPath(path string) (r arrayPathResult) {
return
}
+// splitQuery takes a query and splits it into three parts:
+// path, op, middle, and right.
+// So for this query:
+// #(first_name=="Murphy").last
+// Becomes
+// first_name # path
+// =="Murphy" # middle
+// .last # right
+// Or,
+// #(service_roles.#(=="one")).cap
+// Becomes
+// service_roles.#(=="one") # path
+// # middle
+// .cap # right
+func parseQuery(query string) (
+ path, op, value, remain string, i int, ok bool,
+) {
+ if len(query) < 2 || query[0] != '#' ||
+ (query[1] != '(' && query[1] != '[') {
+ return "", "", "", "", i, false
+ }
+ i = 2
+ j := 0 // start of value part
+ depth := 1
+ for ; i < len(query); i++ {
+ if depth == 1 && j == 0 {
+ switch query[i] {
+ case '!', '=', '<', '>', '%':
+ // start of the value part
+ j = i
+ continue
+ }
+ }
+ if query[i] == '\\' {
+ i++
+ } else if query[i] == '[' || query[i] == '(' {
+ depth++
+ } else if query[i] == ']' || query[i] == ')' {
+ depth--
+ if depth == 0 {
+ break
+ }
+ } else if query[i] == '"' {
+ // inside selector string, balance quotes
+ i++
+ for ; i < len(query); i++ {
+ if query[i] == '\\' {
+ i++
+ } else if query[i] == '"' {
+ break
+ }
+ }
+ }
+ }
+ if depth > 0 {
+ return "", "", "", "", i, false
+ }
+ if j > 0 {
+ path = trim(query[2:j])
+ value = trim(query[j:i])
+ remain = query[i+1:]
+ // parse the compare op from the value
+ var opsz int
+ switch {
+ case len(value) == 1:
+ opsz = 1
+ case value[0] == '!' && value[1] == '=':
+ opsz = 2
+ case value[0] == '!' && value[1] == '%':
+ opsz = 2
+ case value[0] == '<' && value[1] == '=':
+ opsz = 2
+ case value[0] == '>' && value[1] == '=':
+ opsz = 2
+ case value[0] == '=' && value[1] == '=':
+ value = value[1:]
+ opsz = 1
+ case value[0] == '<':
+ opsz = 1
+ case value[0] == '>':
+ opsz = 1
+ case value[0] == '=':
+ opsz = 1
+ case value[0] == '%':
+ opsz = 1
+ }
+ op = value[:opsz]
+ value = trim(value[opsz:])
+ } else {
+ path = trim(query[2:i])
+ remain = query[i+1:]
+ }
+ return path, op, value, remain, i + 1, true
+}
+
+func trim(s string) string {
+left:
+ if len(s) > 0 && s[0] <= ' ' {
+ s = s[1:]
+ goto left
+ }
+right:
+ if len(s) > 0 && s[len(s)-1] <= ' ' {
+ s = s[:len(s)-1]
+ goto right
+ }
+ return s
+}
+
type objectPathResult struct {
- part string
- path string
- wild bool
- more bool
+ part string
+ path string
+ pipe string
+ piped bool
+ wild bool
+ more bool
}
func parseObjectPath(path string) (r objectPathResult) {
for i := 0; i < len(path); i++ {
+ if path[i] == '|' {
+ r.part = path[:i]
+ r.pipe = path[i+1:]
+ r.piped = true
+ return
+ }
if path[i] == '.' {
+ // peek at the next byte and see if it's a '@', '[', or '{'.
r.part = path[:i]
- r.path = path[i+1:]
- r.more = true
+ if !DisableModifiers &&
+ i < len(path)-1 &&
+ (path[i+1] == '@' ||
+ path[i+1] == '[' || path[i+1] == '{') {
+ r.pipe = path[i+1:]
+ r.piped = true
+ } else {
+ r.path = path[i+1:]
+ r.more = true
+ }
return
}
if path[i] == '*' || path[i] == '?' {
@@ -864,9 +1026,22 @@ func parseObjectPath(path string) (r objectPathResult) {
continue
} else if path[i] == '.' {
r.part = string(epart)
- r.path = path[i+1:]
+ // peek at the next byte and see if it's a '@' modifier
+ if !DisableModifiers &&
+ i < len(path)-1 && path[i+1] == '@' {
+ r.pipe = path[i+1:]
+ r.piped = true
+ } else {
+ r.path = path[i+1:]
+ r.more = true
+ }
r.more = true
return
+ } else if path[i] == '|' {
+ r.part = string(epart)
+ r.pipe = path[i+1:]
+ r.piped = true
+ return
} else if path[i] == '*' || path[i] == '?' {
r.wild = true
}
@@ -883,9 +1058,9 @@ func parseObjectPath(path string) (r objectPathResult) {
}
func parseSquash(json string, i int) (int, string) {
- // expects that the lead character is a '[' or '{'
+ // expects that the lead character is a '[' or '{' or '('
// squash the value, ignoring all nested arrays and objects.
- // the first '[' or '{' has already been read
+ // the first '[' or '{' or '(' has already been read
s := i
i++
depth := 1
@@ -916,9 +1091,9 @@ func parseSquash(json string, i int) (int, string) {
break
}
}
- case '{', '[':
+ case '{', '[', '(':
depth++
- case '}', ']':
+ case '}', ']', ')':
depth--
if depth == 0 {
i++
@@ -934,6 +1109,10 @@ func parseObject(c *parseContext, i int, path string) (int, bool) {
var pmatch, kesc, vesc, ok, hit bool
var key, val string
rp := parseObjectPath(path)
+ if !rp.more && rp.piped {
+ c.pipe = rp.pipe
+ c.piped = true
+ }
for i < len(c.json) {
for ; i < len(c.json); i++ {
if c.json[i] == '"' {
@@ -1082,6 +1261,16 @@ func queryMatches(rp *arrayPathResult, value Result) bool {
if len(rpv) > 2 && rpv[0] == '"' && rpv[len(rpv)-1] == '"' {
rpv = rpv[1 : len(rpv)-1]
}
+ if !value.Exists() {
+ return false
+ }
+ if rp.query.op == "" {
+ // the query is only looking for existence, such as:
+ // friends.#(name)
+ // which makes sure that the array "friends" has an element of
+ // "name" that exists
+ return true
+ }
switch value.Type {
case String:
switch rp.query.op {
@@ -1099,6 +1288,8 @@ func queryMatches(rp *arrayPathResult, value Result) bool {
return value.Str >= rpv
case "%":
return match.Match(value.Str, rpv)
+ case "!%":
+ return !match.Match(value.Str, rpv)
}
case Number:
rpvn, _ := strconv.ParseFloat(rpv, 64)
@@ -1157,6 +1348,57 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
partidx = int(n)
}
}
+ if !rp.more && rp.piped {
+ c.pipe = rp.pipe
+ c.piped = true
+ }
+
+ procQuery := func(qval Result) bool {
+ if rp.query.all {
+ if len(multires) == 0 {
+ multires = append(multires, '[')
+ }
+ }
+ var res Result
+ if qval.Type == JSON {
+ res = qval.Get(rp.query.path)
+ } else {
+ if rp.query.path != "" {
+ return false
+ }
+ res = qval
+ }
+ if queryMatches(&rp, res) {
+ if rp.more {
+ left, right, ok := splitPossiblePipe(rp.path)
+ if ok {
+ rp.path = left
+ c.pipe = right
+ c.piped = true
+ }
+ res = qval.Get(rp.path)
+ } else {
+ res = qval
+ }
+ if rp.query.all {
+ raw := res.Raw
+ if len(raw) == 0 {
+ raw = res.String()
+ }
+ if raw != "" {
+ if len(multires) > 1 {
+ multires = append(multires, ',')
+ }
+ multires = append(multires, raw...)
+ }
+ } else {
+ c.value = res
+ return true
+ }
+ }
+ return false
+ }
+
for i < len(c.json)+1 {
if !rp.arrch {
pmatch = partidx == h
@@ -1184,7 +1426,19 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
if !ok {
return i, false
}
- if hit {
+ if rp.query.on {
+ var qval Result
+ if vesc {
+ qval.Str = unescape(val[1 : len(val)-1])
+ } else {
+ qval.Str = val[1 : len(val)-1]
+ }
+ qval.Raw = val
+ qval.Type = String
+ if procQuery(qval) {
+ return i, true
+ }
+ } else if hit {
if rp.alogok {
break
}
@@ -1209,24 +1463,8 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
} else {
i, val = parseSquash(c.json, i)
if rp.query.on {
- res := Get(val, rp.query.path)
- if queryMatches(&rp, res) {
- if rp.more {
- res = Get(val, rp.path)
- } else {
- res = Result{Raw: val, Type: JSON}
- }
- if rp.query.all {
- if len(multires) == 0 {
- multires = append(multires, '[')
- } else {
- multires = append(multires, ',')
- }
- multires = append(multires, res.Raw...)
- } else {
- c.value = res
- return i, true
- }
+ if procQuery(Result{Raw: val, Type: JSON}) {
+ return i, true
}
} else if hit {
if rp.alogok {
@@ -1248,7 +1486,11 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
}
} else {
i, val = parseSquash(c.json, i)
- if hit {
+ if rp.query.on {
+ if procQuery(Result{Raw: val, Type: JSON}) {
+ return i, true
+ }
+ } else if hit {
if rp.alogok {
break
}
@@ -1259,7 +1501,15 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
}
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
i, val = parseNumber(c.json, i)
- if hit {
+ if rp.query.on {
+ var qval Result
+ qval.Raw = val
+ qval.Type = Number
+ qval.Num, _ = strconv.ParseFloat(val, 64)
+ if procQuery(qval) {
+ return i, true
+ }
+ } else if hit {
if rp.alogok {
break
}
@@ -1271,7 +1521,19 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
case 't', 'f', 'n':
vc := c.json[i]
i, val = parseLiteral(c.json, i)
- if hit {
+ if rp.query.on {
+ var qval Result
+ qval.Raw = val
+ switch vc {
+ case 't':
+ qval.Type = True
+ case 'f':
+ qval.Type = False
+ }
+ if procQuery(qval) {
+ return i, true
+ }
+ } else if hit {
if rp.alogok {
break
}
@@ -1287,19 +1549,39 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
case ']':
if rp.arrch && rp.part == "#" {
if rp.alogok {
+ left, right, ok := splitPossiblePipe(rp.alogkey)
+ if ok {
+ rp.alogkey = left
+ c.pipe = right
+ c.piped = true
+ }
var jsons = make([]byte, 0, 64)
jsons = append(jsons, '[')
-
for j, k := 0, 0; j < len(alog); j++ {
- _, res, ok := parseAny(c.json, alog[j], true)
- if ok {
- res := res.Get(rp.alogkey)
- if res.Exists() {
- if k > 0 {
- jsons = append(jsons, ',')
+ idx := alog[j]
+ for idx < len(c.json) {
+ switch c.json[idx] {
+ case ' ', '\t', '\r', '\n':
+ idx++
+ continue
+ }
+ break
+ }
+ if idx < len(c.json) && c.json[idx] != ']' {
+ _, res, ok := parseAny(c.json, idx, true)
+ if ok {
+ res := res.Get(rp.alogkey)
+ if res.Exists() {
+ if k > 0 {
+ jsons = append(jsons, ',')
+ }
+ raw := res.Raw
+ if len(raw) == 0 {
+ raw = res.String()
+ }
+ jsons = append(jsons, []byte(raw)...)
+ k++
}
- jsons = append(jsons, []byte(res.Raw)...)
- k++
}
}
}
@@ -1311,9 +1593,10 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
if rp.alogok {
break
}
- c.value.Raw = ""
+
c.value.Type = Number
c.value.Num = float64(h - 1)
+ c.value.Raw = strconv.Itoa(h - 1)
c.calcd = true
return i + 1, true
}
@@ -1331,6 +1614,88 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
return i, false
}
+func splitPossiblePipe(path string) (left, right string, ok bool) {
+ // take a quick peek for the pipe character. If found we'll split the piped
+ // part of the path into the c.pipe field and shorten the rp.
+ var possible bool
+ for i := 0; i < len(path); i++ {
+ if path[i] == '|' {
+ possible = true
+ break
+ }
+ }
+ if !possible {
+ return
+ }
+
+ if len(path) > 0 && path[0] == '{' {
+ squashed := squash(path[1:])
+ if len(squashed) < len(path)-1 {
+ squashed = path[:len(squashed)+1]
+ remain := path[len(squashed):]
+ if remain[0] == '|' {
+ return squashed, remain[1:], true
+ }
+ }
+ return
+ }
+
+ // split the left and right side of the path with the pipe character as
+ // the delimiter. This is a little tricky because we'll need to basically
+ // parse the entire path.
+ for i := 0; i < len(path); i++ {
+ if path[i] == '\\' {
+ i++
+ } else if path[i] == '.' {
+ if i == len(path)-1 {
+ return
+ }
+ if path[i+1] == '#' {
+ i += 2
+ if i == len(path) {
+ return
+ }
+ if path[i] == '[' || path[i] == '(' {
+ var start, end byte
+ if path[i] == '[' {
+ start, end = '[', ']'
+ } else {
+ start, end = '(', ')'
+ }
+ // inside selector, balance brackets
+ i++
+ depth := 1
+ for ; i < len(path); i++ {
+ if path[i] == '\\' {
+ i++
+ } else if path[i] == start {
+ depth++
+ } else if path[i] == end {
+ depth--
+ if depth == 0 {
+ break
+ }
+ } else if path[i] == '"' {
+ // inside selector string, balance quotes
+ i++
+ for ; i < len(path); i++ {
+ if path[i] == '\\' {
+ i++
+ } else if path[i] == '"' {
+ break
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if path[i] == '|' {
+ return path[:i], path[i+1:], true
+ }
+ }
+ return
+}
+
// ForEachLine iterates through lines of JSON as specified by the JSON Lines
// format (http://jsonlines.org/).
// Each line is returned as a GJSON Result.
@@ -1348,9 +1713,120 @@ func ForEachLine(json string, iterator func(line Result) bool) {
}
}
+type subSelector struct {
+ name string
+ path string
+}
+
+// parseSubSelectors returns the subselectors belonging to a '[path1,path2]' or
+// '{"field1":path1,"field2":path2}' type subSelection. It's expected that the
+// first character in path is either '[' or '{', and has already been checked
+// prior to calling this function.
+func parseSubSelectors(path string) (sels []subSelector, out string, ok bool) {
+ modifer := 0
+ depth := 1
+ colon := 0
+ start := 1
+ i := 1
+ pushSel := func() {
+ var sel subSelector
+ if colon == 0 {
+ sel.path = path[start:i]
+ } else {
+ sel.name = path[start:colon]
+ sel.path = path[colon+1 : i]
+ }
+ sels = append(sels, sel)
+ colon = 0
+ start = i + 1
+ }
+ for ; i < len(path); i++ {
+ switch path[i] {
+ case '\\':
+ i++
+ case '@':
+ if modifer == 0 && i > 0 && (path[i-1] == '.' || path[i-1] == '|') {
+ modifer = i
+ }
+ case ':':
+ if modifer == 0 && colon == 0 && depth == 1 {
+ colon = i
+ }
+ case ',':
+ if depth == 1 {
+ pushSel()
+ }
+ case '"':
+ i++
+ loop:
+ for ; i < len(path); i++ {
+ switch path[i] {
+ case '\\':
+ i++
+ case '"':
+ break loop
+ }
+ }
+ case '[', '(', '{':
+ depth++
+ case ']', ')', '}':
+ depth--
+ if depth == 0 {
+ pushSel()
+ path = path[i+1:]
+ return sels, path, true
+ }
+ }
+ }
+ return
+}
+
+// nameOfLast returns the name of the last component
+func nameOfLast(path string) string {
+ for i := len(path) - 1; i >= 0; i-- {
+ if path[i] == '|' || path[i] == '.' {
+ if i > 0 {
+ if path[i-1] == '\\' {
+ continue
+ }
+ }
+ return path[i+1:]
+ }
+ }
+ return path
+}
+
+func isSimpleName(component string) bool {
+ for i := 0; i < len(component); i++ {
+ if component[i] < ' ' {
+ return false
+ }
+ switch component[i] {
+ case '[', ']', '{', '}', '(', ')', '#', '|':
+ return false
+ }
+ }
+ return true
+}
+
+func appendJSONString(dst []byte, s string) []byte {
+ for i := 0; i < len(s); i++ {
+ if s[i] < ' ' || s[i] == '\\' || s[i] == '"' || s[i] > 126 {
+ d, _ := json.Marshal(s)
+ return append(dst, string(d)...)
+ }
+ }
+ dst = append(dst, '"')
+ dst = append(dst, s...)
+ dst = append(dst, '"')
+ return dst
+}
+
type parseContext struct {
json string
value Result
+ pipe string
+ piped bool
calcd bool
lines bool
}
@@ -1362,7 +1838,8 @@ type parseContext struct {
// A path is a series of keys searated by a dot.
// A key may contain special wildcard characters '*' and '?'.
// To access an array value use the index as the key.
-// To get the number of elements in an array or to access a child path, use the '#' character.
+// To get the number of elements in an array or to access a child path, use
+// the '#' character.
// The dot and wildcard character can be escaped with '\'.
//
// {
@@ -1388,6 +1865,86 @@ type parseContext struct {
// If you are consuming JSON from an unpredictable source then you may want to
// use the Valid function first.
func Get(json, path string) Result {
+ if len(path) > 1 {
+ if !DisableModifiers {
+ if path[0] == '@' {
+ // possible modifier
+ var ok bool
+ var npath string
+ var rjson string
+ npath, rjson, ok = execModifier(json, path)
+ if ok {
+ path = npath
+ if len(path) > 0 && (path[0] == '|' || path[0] == '.') {
+ res := Get(rjson, path[1:])
+ res.Index = 0
+ return res
+ }
+ return Parse(rjson)
+ }
+ }
+ }
+ if path[0] == '[' || path[0] == '{' {
+ // using a subselector path
+ kind := path[0]
+ var ok bool
+ var subs []subSelector
+ subs, path, ok = parseSubSelectors(path)
+ if ok {
+ if len(path) == 0 || (path[0] == '|' || path[0] == '.') {
+ var b []byte
+ b = append(b, kind)
+ var i int
+ for _, sub := range subs {
+ res := Get(json, sub.path)
+ if res.Exists() {
+ if i > 0 {
+ b = append(b, ',')
+ }
+ if kind == '{' {
+ if len(sub.name) > 0 {
+ if sub.name[0] == '"' && Valid(sub.name) {
+ b = append(b, sub.name...)
+ } else {
+ b = appendJSONString(b, sub.name)
+ }
+ } else {
+ last := nameOfLast(sub.path)
+ if isSimpleName(last) {
+ b = appendJSONString(b, last)
+ } else {
+ b = appendJSONString(b, "_")
+ }
+ }
+ b = append(b, ':')
+ }
+ var raw string
+ if len(res.Raw) == 0 {
+ raw = res.String()
+ if len(raw) == 0 {
+ raw = "null"
+ }
+ } else {
+ raw = res.Raw
+ }
+ b = append(b, raw...)
+ i++
+ }
+ }
+ b = append(b, kind+2)
+ var res Result
+ res.Raw = string(b)
+ res.Type = JSON
+ if len(path) > 0 {
+ res = res.Get(path[1:])
+ }
+ res.Index = 0
+ return res
+ }
+ }
+ }
+ }
+
var i int
var c = &parseContext{json: json}
if len(path) >= 2 && path[0] == '.' && path[1] == '.' {
@@ -1407,6 +1964,11 @@ func Get(json, path string) Result {
}
}
}
+ if c.piped {
+ res := c.value.Get(c.pipe)
+ res.Index = 0
+ return res
+ }
fillIndex(json, c)
return c.value
}
@@ -1424,7 +1986,7 @@ func runeit(json string) rune {
}
// unescape unescapes a string
-func unescape(json string) string { //, error) {
+func unescape(json string) string {
var str = make([]byte, 0, len(json))
for i := 0; i < len(json); i++ {
switch {
@@ -1464,7 +2026,8 @@ func unescape(json string) string { //, error) {
i += 5
if utf16.IsSurrogate(r) {
// need another code
- if len(json[i:]) >= 6 && json[i] == '\\' && json[i+1] == 'u' {
+ if len(json[i:]) >= 6 && json[i] == '\\' &&
+ json[i+1] == 'u' {
// we expect it to be correct so just consume it
r = utf16.DecodeRune(r, runeit(json[i+2:]))
i += 6
@@ -1626,141 +2189,11 @@ func GetMany(json string, path ...string) []Result {
// The return value is a Result array where the number of items
// will be equal to the number of input paths.
func GetManyBytes(json []byte, path ...string) []Result {
- return GetMany(string(json), path...)
-}
-
-var fieldsmu sync.RWMutex
-var fields = make(map[string]map[string]int)
-
-func assign(jsval Result, goval reflect.Value) {
- if jsval.Type == Null {
- return
- }
- switch goval.Kind() {
- default:
- case reflect.Ptr:
- if !goval.IsNil() {
- newval := reflect.New(goval.Elem().Type())
- assign(jsval, newval.Elem())
- goval.Elem().Set(newval.Elem())
- } else {
- newval := reflect.New(goval.Type().Elem())
- assign(jsval, newval.Elem())
- goval.Set(newval)
- }
- case reflect.Struct:
- fieldsmu.RLock()
- sf := fields[goval.Type().String()]
- fieldsmu.RUnlock()
- if sf == nil {
- fieldsmu.Lock()
- sf = make(map[string]int)
- for i := 0; i < goval.Type().NumField(); i++ {
- f := goval.Type().Field(i)
- tag := strings.Split(f.Tag.Get("json"), ",")[0]
- if tag != "-" {
- if tag != "" {
- sf[tag] = i
- sf[f.Name] = i
- } else {
- sf[f.Name] = i
- }
- }
- }
- fields[goval.Type().String()] = sf
- fieldsmu.Unlock()
- }
- jsval.ForEach(func(key, value Result) bool {
- if idx, ok := sf[key.Str]; ok {
- f := goval.Field(idx)
- if f.CanSet() {
- assign(value, f)
- }
- }
- return true
- })
- case reflect.Slice:
- if goval.Type().Elem().Kind() == reflect.Uint8 && jsval.Type == String {
- data, _ := base64.StdEncoding.DecodeString(jsval.String())
- goval.Set(reflect.ValueOf(data))
- } else {
- jsvals := jsval.Array()
- slice := reflect.MakeSlice(goval.Type(), len(jsvals), len(jsvals))
- for i := 0; i < len(jsvals); i++ {
- assign(jsvals[i], slice.Index(i))
- }
- goval.Set(slice)
- }
- case reflect.Array:
- i, n := 0, goval.Len()
- jsval.ForEach(func(_, value Result) bool {
- if i == n {
- return false
- }
- assign(value, goval.Index(i))
- i++
- return true
- })
- case reflect.Map:
- if goval.Type().Key().Kind() == reflect.String && goval.Type().Elem().Kind() == reflect.Interface {
- goval.Set(reflect.ValueOf(jsval.Value()))
- }
- case reflect.Interface:
- goval.Set(reflect.ValueOf(jsval.Value()))
- case reflect.Bool:
- goval.SetBool(jsval.Bool())
- case reflect.Float32, reflect.Float64:
- goval.SetFloat(jsval.Float())
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- goval.SetInt(jsval.Int())
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- goval.SetUint(jsval.Uint())
- case reflect.String:
- goval.SetString(jsval.String())
- }
- if len(goval.Type().PkgPath()) > 0 {
- v := goval.Addr()
- if v.Type().NumMethod() > 0 {
- if u, ok := v.Interface().(json.Unmarshaler); ok {
- u.UnmarshalJSON([]byte(jsval.Raw))
- }
- }
- }
-}
-
-var validate uintptr = 1
-
-// UnmarshalValidationEnabled provides the option to disable JSON validation
-// during the Unmarshal routine. Validation is enabled by default.
-//
-// Deprecated: Use encoder/json.Unmarshal instead
-func UnmarshalValidationEnabled(enabled bool) {
- if enabled {
- atomic.StoreUintptr(&validate, 1)
- } else {
- atomic.StoreUintptr(&validate, 0)
- }
-}
-
-// Unmarshal loads the JSON data into the value pointed to by v.
-//
-// This function works almost identically to json.Unmarshal except that
-// gjson.Unmarshal will automatically attempt to convert JSON values to any Go
-// type. For example, the JSON string "100" or the JSON number 100 can be equally
-// assigned to Go string, int, byte, uint64, etc. This rule applies to all types.
-//
-// Deprecated: Use encoder/json.Unmarshal instead
-func Unmarshal(data []byte, v interface{}) error {
- if atomic.LoadUintptr(&validate) == 1 {
- _, ok := validpayload(data, 0)
- if !ok {
- return errors.New("invalid json")
- }
- }
- if v := reflect.ValueOf(v); v.Kind() == reflect.Ptr {
- assign(ParseBytes(data), v)
+ res := make([]Result, len(path))
+ for i, path := range path {
+ res[i] = GetBytes(json, path)
}
- return nil
+ return res
}
func validpayload(data []byte, i int) (outi int, ok bool) {
@@ -2006,19 +2439,22 @@ func validnumber(data []byte, i int) (outi int, ok bool) {
}
func validtrue(data []byte, i int) (outi int, ok bool) {
- if i+3 <= len(data) && data[i] == 'r' && data[i+1] == 'u' && data[i+2] == 'e' {
+ if i+3 <= len(data) && data[i] == 'r' && data[i+1] == 'u' &&
+ data[i+2] == 'e' {
return i + 3, true
}
return i, false
}
func validfalse(data []byte, i int) (outi int, ok bool) {
- if i+4 <= len(data) && data[i] == 'a' && data[i+1] == 'l' && data[i+2] == 's' && data[i+3] == 'e' {
+ if i+4 <= len(data) && data[i] == 'a' && data[i+1] == 'l' &&
+ data[i+2] == 's' && data[i+3] == 'e' {
return i + 4, true
}
return i, false
}
func validnull(data []byte, i int) (outi int, ok bool) {
- if i+3 <= len(data) && data[i] == 'u' && data[i+1] == 'l' && data[i+2] == 'l' {
+ if i+3 <= len(data) && data[i] == 'u' && data[i+1] == 'l' &&
+ data[i+2] == 'l' {
return i + 3, true
}
return i, false
@@ -2032,7 +2468,7 @@ func validnull(data []byte, i int) (outi int, ok bool) {
// value := gjson.Get(json, "name.last")
//
func Valid(json string) bool {
- _, ok := validpayload([]byte(json), 0)
+ _, ok := validpayload(stringBytes(json), 0)
return ok
}
@@ -2043,7 +2479,7 @@ func Valid(json string) bool {
// }
// value := gjson.Get(json, "name.last")
//
-// If working with bytes, this method preferred over Valid(string(data))
+// If working with bytes, this method preferred over ValidBytes(string(data))
//
func ValidBytes(json []byte) bool {
_, ok := validpayload(json, 0)
@@ -2108,3 +2544,355 @@ func floatToInt(f float64) (n int64, ok bool) {
}
return 0, false
}
+
+// execModifier parses the path to find a matching modifier function.
+// then input expects that the path already starts with a '@'
+func execModifier(json, path string) (pathOut, res string, ok bool) {
+ name := path[1:]
+ var hasArgs bool
+ for i := 1; i < len(path); i++ {
+ if path[i] == ':' {
+ pathOut = path[i+1:]
+ name = path[1:i]
+ hasArgs = len(pathOut) > 0
+ break
+ }
+ if path[i] == '|' {
+ pathOut = path[i:]
+ name = path[1:i]
+ break
+ }
+ if path[i] == '.' {
+ pathOut = path[i:]
+ name = path[1:i]
+ break
+ }
+ }
+ if fn, ok := modifiers[name]; ok {
+ var args string
+ if hasArgs {
+ var parsedArgs bool
+ switch pathOut[0] {
+ case '{', '[', '"':
+ res := Parse(pathOut)
+ if res.Exists() {
+ args = squash(pathOut)
+ pathOut = pathOut[len(args):]
+ parsedArgs = true
+ }
+ }
+ if !parsedArgs {
+ idx := strings.IndexByte(pathOut, '|')
+ if idx == -1 {
+ args = pathOut
+ pathOut = ""
+ } else {
+ args = pathOut[:idx]
+ pathOut = pathOut[idx:]
+ }
+ }
+ }
+ return pathOut, fn(json, args), true
+ }
+ return pathOut, res, false
+}
+
+// unwrap removes the '[]' or '{}' characters around json
+func unwrap(json string) string {
+ json = trim(json)
+ if len(json) >= 2 && json[0] == '[' || json[0] == '{' {
+ json = json[1 : len(json)-1]
+ }
+ return json
+}
+
+// DisableModifiers will disable the modifier syntax
+var DisableModifiers = false
+
+var modifiers = map[string]func(json, arg string) string{
+ "pretty": modPretty,
+ "ugly": modUgly,
+ "reverse": modReverse,
+ "this": modThis,
+ "flatten": modFlatten,
+ "join": modJoin,
+ "valid": modValid,
+}
+
+// AddModifier binds a custom modifier command to the GJSON syntax.
+// This operation is not thread safe and should be executed prior to
+// using all other gjson function.
+func AddModifier(name string, fn func(json, arg string) string) {
+ modifiers[name] = fn
+}
+
+// ModifierExists returns true when the specified modifier exists.
+func ModifierExists(name string, fn func(json, arg string) string) bool {
+ _, ok := modifiers[name]
+ return ok
+}
+
+// @pretty modifier makes the json look nice.
+func modPretty(json, arg string) string {
+ if len(arg) > 0 {
+ opts := *pretty.DefaultOptions
+ Parse(arg).ForEach(func(key, value Result) bool {
+ switch key.String() {
+ case "sortKeys":
+ opts.SortKeys = value.Bool()
+ case "indent":
+ opts.Indent = value.String()
+ case "prefix":
+ opts.Prefix = value.String()
+ case "width":
+ opts.Width = int(value.Int())
+ }
+ return true
+ })
+ return bytesString(pretty.PrettyOptions(stringBytes(json), &opts))
+ }
+ return bytesString(pretty.Pretty(stringBytes(json)))
+}
+
+// @this returns the current element. Can be used to retrieve the root element.
+func modThis(json, arg string) string {
+ return json
+}
+
+// @ugly modifier removes all whitespace.
+func modUgly(json, arg string) string {
+ return bytesString(pretty.Ugly(stringBytes(json)))
+}
+
+// @reverse reverses array elements or root object members.
+func modReverse(json, arg string) string {
+ res := Parse(json)
+ if res.IsArray() {
+ var values []Result
+ res.ForEach(func(_, value Result) bool {
+ values = append(values, value)
+ return true
+ })
+ out := make([]byte, 0, len(json))
+ out = append(out, '[')
+ for i, j := len(values)-1, 0; i >= 0; i, j = i-1, j+1 {
+ if j > 0 {
+ out = append(out, ',')
+ }
+ out = append(out, values[i].Raw...)
+ }
+ out = append(out, ']')
+ return bytesString(out)
+ }
+ if res.IsObject() {
+ var keyValues []Result
+ res.ForEach(func(key, value Result) bool {
+ keyValues = append(keyValues, key, value)
+ return true
+ })
+ out := make([]byte, 0, len(json))
+ out = append(out, '{')
+ for i, j := len(keyValues)-2, 0; i >= 0; i, j = i-2, j+1 {
+ if j > 0 {
+ out = append(out, ',')
+ }
+ out = append(out, keyValues[i+0].Raw...)
+ out = append(out, ':')
+ out = append(out, keyValues[i+1].Raw...)
+ }
+ out = append(out, '}')
+ return bytesString(out)
+ }
+ return json
+}
+
+// @flatten an array with child arrays.
+// [1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,[6,7]]
+// The {"deep":true} arg can be provide for deep flattening.
+// [1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,6,7]
+// The original json is returned when the json is not an array.
+func modFlatten(json, arg string) string {
+ res := Parse(json)
+ if !res.IsArray() {
+ return json
+ }
+ var deep bool
+ if arg != "" {
+ Parse(arg).ForEach(func(key, value Result) bool {
+ if key.String() == "deep" {
+ deep = value.Bool()
+ }
+ return true
+ })
+ }
+ var out []byte
+ out = append(out, '[')
+ var idx int
+ res.ForEach(func(_, value Result) bool {
+ if idx > 0 {
+ out = append(out, ',')
+ }
+ if value.IsArray() {
+ if deep {
+ out = append(out, unwrap(modFlatten(value.Raw, arg))...)
+ } else {
+ out = append(out, unwrap(value.Raw)...)
+ }
+ } else {
+ out = append(out, value.Raw...)
+ }
+ idx++
+ return true
+ })
+ out = append(out, ']')
+ return bytesString(out)
+}
+
+// @join multiple objects into a single object.
+// [{"first":"Tom"},{"last":"Smith"}] -> {"first","Tom","last":"Smith"}
+// The arg can be "true" to specify that duplicate keys should be preserved.
+// [{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":37,"age":41}
+// Without preserved keys:
+// [{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":41}
+// The original json is returned when the json is not an object.
+func modJoin(json, arg string) string {
+ res := Parse(json)
+ if !res.IsArray() {
+ return json
+ }
+ var preserve bool
+ if arg != "" {
+ Parse(arg).ForEach(func(key, value Result) bool {
+ if key.String() == "preserve" {
+ preserve = value.Bool()
+ }
+ return true
+ })
+ }
+ var out []byte
+ out = append(out, '{')
+ if preserve {
+ // Preserve duplicate keys.
+ var idx int
+ res.ForEach(func(_, value Result) bool {
+ if !value.IsObject() {
+ return true
+ }
+ if idx > 0 {
+ out = append(out, ',')
+ }
+ out = append(out, unwrap(value.Raw)...)
+ idx++
+ return true
+ })
+ } else {
+ // Deduplicate keys and generate an object with stable ordering.
+ var keys []Result
+ kvals := make(map[string]Result)
+ res.ForEach(func(_, value Result) bool {
+ if !value.IsObject() {
+ return true
+ }
+ value.ForEach(func(key, value Result) bool {
+ k := key.String()
+ if _, ok := kvals[k]; !ok {
+ keys = append(keys, key)
+ }
+ kvals[k] = value
+ return true
+ })
+ return true
+ })
+ for i := 0; i < len(keys); i++ {
+ if i > 0 {
+ out = append(out, ',')
+ }
+ out = append(out, keys[i].Raw...)
+ out = append(out, ':')
+ out = append(out, kvals[keys[i].String()].Raw...)
+ }
+ }
+ out = append(out, '}')
+ return bytesString(out)
+}
+
+// @valid ensures that the json is valid before moving on. An empty string is
+// returned when the json is not valid, otherwise it returns the original json.
+func modValid(json, arg string) string {
+ if !Valid(json) {
+ return ""
+ }
+ return json
+}
+
+// getBytes casts the input json bytes to a string and safely returns the
+// results as uniquely allocated data. This operation is intended to minimize
+// copies and allocations for the large json string->[]byte.
+func getBytes(json []byte, path string) Result {
+ var result Result
+ if json != nil {
+ // unsafe cast to string
+ result = Get(*(*string)(unsafe.Pointer(&json)), path)
+ // safely get the string headers
+ rawhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Raw))
+ strhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Str))
+ // create byte slice headers
+ rawh := reflect.SliceHeader{Data: rawhi.Data, Len: rawhi.Len}
+ strh := reflect.SliceHeader{Data: strhi.Data, Len: strhi.Len}
+ if strh.Data == 0 {
+ // str is nil
+ if rawh.Data == 0 {
+ // raw is nil
+ result.Raw = ""
+ } else {
+ // raw has data, safely copy the slice header to a string
+ result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
+ }
+ result.Str = ""
+ } else if rawh.Data == 0 {
+ // raw is nil
+ result.Raw = ""
+ // str has data, safely copy the slice header to a string
+ result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
+ } else if strh.Data >= rawh.Data &&
+ int(strh.Data)+strh.Len <= int(rawh.Data)+rawh.Len {
+ // Str is a substring of Raw.
+ start := int(strh.Data - rawh.Data)
+ // safely copy the raw slice header
+ result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
+ // substring the raw
+ result.Str = result.Raw[start : start+strh.Len]
+ } else {
+ // safely copy both the raw and str slice headers to strings
+ result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
+ result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
+ }
+ }
+ return result
+}
+
+// fillIndex finds the position of Raw data and assigns it to the Index field
+// of the resulting value. If the position cannot be found then Index zero is
+// used instead.
+func fillIndex(json string, c *parseContext) {
+ if len(c.value.Raw) > 0 && !c.calcd {
+ jhdr := *(*reflect.StringHeader)(unsafe.Pointer(&json))
+ rhdr := *(*reflect.StringHeader)(unsafe.Pointer(&(c.value.Raw)))
+ c.value.Index = int(rhdr.Data - jhdr.Data)
+ if c.value.Index < 0 || c.value.Index >= len(json) {
+ c.value.Index = 0
+ }
+ }
+}
+
+func stringBytes(s string) []byte {
+ return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
+ Data: (*reflect.StringHeader)(unsafe.Pointer(&s)).Data,
+ Len: len(s),
+ Cap: len(s),
+ }))
+}
+
+func bytesString(b []byte) string {
+ return *(*string)(unsafe.Pointer(&b))
+}
diff --git a/vendor/github.com/tidwall/gjson/gjson_gae.go b/vendor/github.com/tidwall/gjson/gjson_gae.go
deleted file mode 100644
index cbe2ab420b..0000000000
--- a/vendor/github.com/tidwall/gjson/gjson_gae.go
+++ /dev/null
@@ -1,10 +0,0 @@
-//+build appengine
-
-package gjson
-
-func getBytes(json []byte, path string) Result {
- return Get(string(json), path)
-}
-func fillIndex(json string, c *parseContext) {
- // noop. Use zero for the Index value.
-}
diff --git a/vendor/github.com/tidwall/gjson/gjson_ngae.go b/vendor/github.com/tidwall/gjson/gjson_ngae.go
deleted file mode 100644
index ff313a7879..0000000000
--- a/vendor/github.com/tidwall/gjson/gjson_ngae.go
+++ /dev/null
@@ -1,73 +0,0 @@
-//+build !appengine
-
-package gjson
-
-import (
- "reflect"
- "unsafe"
-)
-
-// getBytes casts the input json bytes to a string and safely returns the
-// results as uniquely allocated data. This operation is intended to minimize
-// copies and allocations for the large json string->[]byte.
-func getBytes(json []byte, path string) Result {
- var result Result
- if json != nil {
- // unsafe cast to string
- result = Get(*(*string)(unsafe.Pointer(&json)), path)
- result = fromBytesGet(result)
- }
- return result
-}
-
-func fromBytesGet(result Result) Result {
- // safely get the string headers
- rawhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Raw))
- strhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Str))
- // create byte slice headers
- rawh := reflect.SliceHeader{Data: rawhi.Data, Len: rawhi.Len}
- strh := reflect.SliceHeader{Data: strhi.Data, Len: strhi.Len}
- if strh.Data == 0 {
- // str is nil
- if rawh.Data == 0 {
- // raw is nil
- result.Raw = ""
- } else {
- // raw has data, safely copy the slice header to a string
- result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
- }
- result.Str = ""
- } else if rawh.Data == 0 {
- // raw is nil
- result.Raw = ""
- // str has data, safely copy the slice header to a string
- result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
- } else if strh.Data >= rawh.Data &&
- int(strh.Data)+strh.Len <= int(rawh.Data)+rawh.Len {
- // Str is a substring of Raw.
- start := int(strh.Data - rawh.Data)
- // safely copy the raw slice header
- result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
- // substring the raw
- result.Str = result.Raw[start : start+strh.Len]
- } else {
- // safely copy both the raw and str slice headers to strings
- result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
- result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
- }
- return result
-}
-
-// fillIndex finds the position of Raw data and assigns it to the Index field
-// of the resulting value. If the position cannot be found then Index zero is
-// used instead.
-func fillIndex(json string, c *parseContext) {
- if len(c.value.Raw) > 0 && !c.calcd {
- jhdr := *(*reflect.StringHeader)(unsafe.Pointer(&json))
- rhdr := *(*reflect.StringHeader)(unsafe.Pointer(&(c.value.Raw)))
- c.value.Index = int(rhdr.Data - jhdr.Data)
- if c.value.Index < 0 || c.value.Index >= len(json) {
- c.value.Index = 0
- }
- }
-}
diff --git a/vendor/github.com/tidwall/gjson/go.mod b/vendor/github.com/tidwall/gjson/go.mod
new file mode 100644
index 0000000000..c287095fc5
--- /dev/null
+++ b/vendor/github.com/tidwall/gjson/go.mod
@@ -0,0 +1,8 @@
+module github.com/tidwall/gjson
+
+go 1.12
+
+require (
+ github.com/tidwall/match v1.0.1
+ github.com/tidwall/pretty v1.0.2
+)
diff --git a/vendor/github.com/tidwall/gjson/go.sum b/vendor/github.com/tidwall/gjson/go.sum
new file mode 100644
index 0000000000..75e1dd7b72
--- /dev/null
+++ b/vendor/github.com/tidwall/gjson/go.sum
@@ -0,0 +1,4 @@
+github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
+github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
+github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
+github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
diff --git a/vendor/github.com/tidwall/match/match.go b/vendor/github.com/tidwall/match/match.go
index 8885add63c..fcfe998b5b 100644
--- a/vendor/github.com/tidwall/match/match.go
+++ b/vendor/github.com/tidwall/match/match.go
@@ -168,25 +168,14 @@ func Allowable(pattern string) (min, max string) {
}
}
return string(minb), string(maxb)
- /*
- return
- if wild {
- r, n := utf8.DecodeLastRune(maxb)
- if r != utf8.RuneError {
- if r < utf8.MaxRune {
- infinite = true
- } else {
- r++
- if r > 0x7f {
- b := make([]byte, 4)
- nn := utf8.EncodeRune(b, r)
- maxb = append(maxb[:len(maxb)-n], b[:nn]...)
- } else {
- maxb = append(maxb[:len(maxb)-n], byte(r))
- }
- }
- }
+}
+
+// IsPattern returns true if the string is a pattern.
+func IsPattern(str string) bool {
+ for i := 0; i < len(str); i++ {
+ if str[i] == '*' || str[i] == '?' {
+ return true
}
- return string(minb), string(maxb), infinite
- */
+ }
+ return false
}
diff --git a/vendor/github.com/tidwall/pretty/README.md b/vendor/github.com/tidwall/pretty/README.md
index d2b8864d50..09884692e1 100644
--- a/vendor/github.com/tidwall/pretty/README.md
+++ b/vendor/github.com/tidwall/pretty/README.md
@@ -1,7 +1,7 @@
# Pretty
[](https://travis-ci.org/tidwall/prettty)
[](http://gocover.io/github.com/tidwall/pretty)
-[](https://godoc.org/github.com/tidwall/pretty)
+[](https://pkg.go.dev/github.com/tidwall/pretty)
Pretty is a Go package that provides [fast](#performance) methods for formatting JSON for human readability, or to compact JSON for smaller payloads.
diff --git a/vendor/github.com/tidwall/pretty/pretty.go b/vendor/github.com/tidwall/pretty/pretty.go
index 5b615bc763..2951c610ea 100644
--- a/vendor/github.com/tidwall/pretty/pretty.go
+++ b/vendor/github.com/tidwall/pretty/pretty.go
@@ -186,7 +186,7 @@ func appendPrettyObject(buf, json []byte, i int, open, close byte, pretty bool,
if open == '[' || json[i] == '"' {
if n > 0 {
buf = append(buf, ',')
- if width != -1 {
+ if width != -1 && open == '[' {
buf = append(buf, ' ')
}
}
@@ -318,21 +318,25 @@ func hexp(p byte) byte {
}
// TerminalStyle is for terminals
-var TerminalStyle = &Style{
- Key: [2]string{"\x1B[94m", "\x1B[0m"},
- String: [2]string{"\x1B[92m", "\x1B[0m"},
- Number: [2]string{"\x1B[93m", "\x1B[0m"},
- True: [2]string{"\x1B[96m", "\x1B[0m"},
- False: [2]string{"\x1B[96m", "\x1B[0m"},
- Null: [2]string{"\x1B[91m", "\x1B[0m"},
- Append: func(dst []byte, c byte) []byte {
- if c < ' ' && (c != '\r' && c != '\n' && c != '\t' && c != '\v') {
- dst = append(dst, "\\u00"...)
- dst = append(dst, hexp((c>>4)&0xF))
- return append(dst, hexp((c)&0xF))
- }
- return append(dst, c)
- },
+var TerminalStyle *Style
+
+func init() {
+ TerminalStyle = &Style{
+ Key: [2]string{"\x1B[94m", "\x1B[0m"},
+ String: [2]string{"\x1B[92m", "\x1B[0m"},
+ Number: [2]string{"\x1B[93m", "\x1B[0m"},
+ True: [2]string{"\x1B[96m", "\x1B[0m"},
+ False: [2]string{"\x1B[96m", "\x1B[0m"},
+ Null: [2]string{"\x1B[91m", "\x1B[0m"},
+ Append: func(dst []byte, c byte) []byte {
+ if c < ' ' && (c != '\r' && c != '\n' && c != '\t' && c != '\v') {
+ dst = append(dst, "\\u00"...)
+ dst = append(dst, hexp((c>>4)&0xF))
+ return append(dst, hexp((c)&0xF))
+ }
+ return append(dst, c)
+ },
+ }
}
// Color will colorize the json. The style parma is used for customizing
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 5f011f813d..8c60f54c7e 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -30,11 +30,11 @@ github.com/andybalholm/cascadia
github.com/daaku/go.zipexe
# github.com/davecgh/go-spew v1.1.1 => github.com/davecgh/go-spew v1.1.0
github.com/davecgh/go-spew/spew
-# github.com/dlclark/regexp2 v1.2.1-0.20200807145002-74bac81f00cf
+# github.com/dlclark/regexp2 v1.4.0
## explicit
github.com/dlclark/regexp2
github.com/dlclark/regexp2/syntax
-# github.com/dop251/goja v0.0.0-20200831102558-9af81ddcf0e1
+# github.com/dop251/goja v0.0.0-20201007100345-a8e472c705eb
## explicit
github.com/dop251/goja
github.com/dop251/goja/ast
@@ -73,7 +73,7 @@ github.com/gin-contrib/sse
github.com/gin-gonic/gin
github.com/gin-gonic/gin/binding
github.com/gin-gonic/gin/render
-# github.com/go-sourcemap/sourcemap v2.1.2+incompatible
+# github.com/go-sourcemap/sourcemap v2.1.3+incompatible
## explicit
github.com/go-sourcemap/sourcemap
github.com/go-sourcemap/sourcemap/internal/base64vlq
@@ -205,13 +205,12 @@ github.com/spf13/pflag
## explicit
github.com/stretchr/testify/assert
github.com/stretchr/testify/require
-# github.com/tidwall/gjson v1.1.3
+# github.com/tidwall/gjson v1.6.1
## explicit
github.com/tidwall/gjson
-# github.com/tidwall/match v1.0.0
-## explicit
+# github.com/tidwall/match v1.0.1
github.com/tidwall/match
-# github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51
+# github.com/tidwall/pretty v1.0.2
## explicit
github.com/tidwall/pretty
# github.com/ugorji/go v1.1.7 => github.com/ugorji/go v0.0.0-20180112141927-9831f2c3ac10
@@ -252,7 +251,7 @@ golang.org/x/net/idna
# golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 => golang.org/x/sys v0.0.0-20180312081825-c28acc882ebc
golang.org/x/sys/unix
golang.org/x/sys/windows
-# golang.org/x/text v0.3.2 => golang.org/x/text v0.3.0
+# golang.org/x/text v0.3.3 => golang.org/x/text v0.3.0
## explicit
golang.org/x/text/cases
golang.org/x/text/collate