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 [![Build Status](https://img.shields.io/travis/tidwall/pretty.svg?style=flat-square)](https://travis-ci.org/tidwall/prettty) [![Coverage Status](https://img.shields.io/badge/coverage-100%25-brightgreen.svg?style=flat-square)](http://gocover.io/github.com/tidwall/pretty) -[![GoDoc](https://img.shields.io/badge/api-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/tidwall/pretty) +[![GoDoc](https://img.shields.io/badge/api-reference-blue.svg?style=flat-square)](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