[
  {
    "path": ".github/dependabot.yml",
    "content": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where the package manifests are located.\n# Please see the documentation for all configuration options:\n# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n  - package-ecosystem: \"github-actions\" # See documentation for possible values\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"weekly\"\n\n# $Hash:c5d3212bc9191230f44684f4d30f030b6c70d515e68cbc9c3467c4d9$\n"
  },
  {
    "path": ".github/workflows/go.yml",
    "content": "name: Go\n\non: [push]\n\npermissions:\n  contents: write\n\nenv:\n  GO_VERSION: 'oldstable'\n\njobs:\n\n  check:\n    name: Check main packages\n    outputs:\n      targets: ${{ steps.list.outputs.targets }}\n\n    runs-on: ubuntu-latest\n\n    steps:\n\n    - uses: actions/checkout@v6\n    - uses: actions/setup-go@v6\n      with:\n        go-version: ${{ env.GO_VERSION }}\n\n    - name: List \"main\" packages to be released\n      id: list\n      shell: bash\n      run: |\n        found=0\n        echo \"targets<<__END__\" >> \"$GITHUB_OUTPUT\"\n        main_packages=$(go list -f '{{if (eq .Name \"main\")}}{{.ImportPath}} .{{slice .ImportPath (len .Module.Path)}}{{end}}' ./...)\n        while read -r path dir; do\n          [ -z \"$path\" ] && continue\n          name=$(basename \"$path\")\n          if [ -f \"$dir/.norelease\" ] ; then\n            printf \"Skipped %s\\t(%s), due to %s/.norelease found\\n\" \"$name\" \"$dir\" \"$dir\"\n          else\n            found=1\n            echo \"$name $dir $path\" >> \"$GITHUB_OUTPUT\"\n            printf \"Added   %s\\t(%s) to the release\\n\" \"$name\" \"$dir\"\n          fi\n        done <<EOF\n        $main_packages\n        EOF\n        echo \"__END__\" >> \"$GITHUB_OUTPUT\"\n        if [ $found -eq 0 ] ; then\n          echo \"⛔ No packages found to release\"\n        fi\n\n  build:\n    name: Build\n\n    needs: check\n\n    env:\n      RELEASE_TARGETS: ${{needs.check.outputs.targets}}\n\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n        - { os: darwin,  arch: amd64, runner: macos-latest,     }\n        - { os: darwin,  arch: arm64, runner: macos-latest,     }\n        - { os: freebsd, arch: amd64, runner: ubuntu-latest,    }\n        - { os: linux,   arch: arm64, runner: ubuntu-24.04-arm, }\n        - { os: linux,   arch: amd64, runner: ubuntu-latest,    }\n        - { os: windows, arch: amd64, runner: windows-latest,   }\n\n    defaults:\n      run:\n        shell: ${{ matrix.os == 'freebsd' && 'freebsd {0}' || 'bash' }}\n\n    runs-on: ${{ matrix.runner }}\n\n    steps:\n\n    - uses: actions/checkout@v6\n\n    - uses: actions/setup-go@v6\n      with:\n        go-version: ${{ env.GO_VERSION }}\n\n    - name: Setup env\n      id: setup\n      shell: bash\n      run: |\n        NAME=\"${GITHUB_REPOSITORY#${GITHUB_REPOSITORY_OWNER}/}\"\n\n        GOOS=${{ matrix.os }}\n        GOARCH=${{ matrix.arch }}\n\n        if [[ ${GITHUB_REF} =~ ^refs/tags/v[0-9]+\\.[0-9]+ ]] ; then\n          VERSION=${GITHUB_REF_NAME}\n        else\n          VERSION=SNAPSHOT\n        fi\n\n        case ${{ matrix.os }} in\n          linux|freebsd)  PKGEXT=.tar.gz ;;\n          darwin|windows) PKGEXT=.zip ;;\n        esac\n\n        case ${{ matrix.os }} in\n          windows) choco install zip ;;\n        esac\n\n        echo \"VERSION=${VERSION}\" >> $GITHUB_ENV\n        echo \"GOOS=${GOOS}\" >> $GITHUB_ENV\n        echo \"GOARCH=${GOARCH}\" >> $GITHUB_ENV\n        echo \"CGO_ENABLED=1\" >> $GITHUB_ENV\n        echo \"PKGNAME=${NAME}_${VERSION}_${GOOS}_${GOARCH}\" >> $GITHUB_ENV\n        echo \"PKGEXT=${PKGEXT}\" >> $GITHUB_ENV\n\n    - name: Start FreeBSD VM\n      if: matrix.os == 'freebsd'\n      uses: vmactions/freebsd-vm@d1e65811565151536c0c894fff74f06351ed26e6 # v1.4.5\n      with:\n        usesh: true\n        copyback: false\n        disable-cache: true\n        arch: ${{ matrix.arch }}\n\n        envs: 'RELEASE_TARGETS PKGNAME PKGEXT'\n\n        prepare: |\n          echo \"::group::Install Go\"\n          pkg install -y go\n\n    - name: Test all\n      run: |\n        go test ./...\n\n    - name: Build all \"main\" packages\n      if: needs.check.outputs.targets != ''\n      run: |\n        while read -r name dir path ; do\n          printf \"building %s\\t(%s)\\n\" \"$name\" \"$dir\"\n          ( cd \"$dir\" && go build )\n        done <<EOF\n        $RELEASE_TARGETS\n        EOF\n\n    - name: Copyback from FreeBSD VM\n      if: matrix.os == 'freebsd' && needs.check.outputs.targets != ''\n      shell: bash\n      run: |\n        rsync -av --exclude .git -e ssh \"freebsd:$HOME/work/\" \"$HOME/work/\"\n\n    - name: Archive\n      if: needs.check.outputs.targets != ''\n      shell: bash\n      run: |\n        mkdir -p _build/${PKGNAME}\n\n        while read -r name dir path ; do\n          cp \"$dir/$name\" _build/${PKGNAME}\n        done <<EOF\n        $RELEASE_TARGETS\n        EOF\n\n        cp -p LICENSE _build/${PKGNAME}\n        cp -p README.md _build/${PKGNAME}\n\n        case \"${PKGEXT}\" in\n          \".tar.gz\")\n            tar caf _build/${PKGNAME}${PKGEXT} -C _build ${PKGNAME}\n            ;;\n          \".zip\")\n            (cd _build && zip -r9q ${PKGNAME}${PKGEXT} ${PKGNAME})\n            ;;\n        esac\n        ls -laFR _build\n\n    - name: Artifact upload\n      if: needs.check.outputs.targets != ''\n      uses: actions/upload-artifact@v7\n      with:\n        name: release-${{ env.GOOS }}_${{ env.GOARCH }}\n        path: _build/${{ env.PKGNAME }}${{ env.PKGEXT }}\n\n  create-release:\n    name: Create release\n    runs-on: ubuntu-latest\n    if: startsWith(github.ref, 'refs/tags/')\n    needs:\n    - build\n    steps:\n    - uses: actions/download-artifact@v8\n      with:\n        pattern: release-*\n        merge-multiple: true\n    - run: ls -lafR\n    - name: Release\n      uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0\n      with:\n        draft: true\n        prerelease: ${{ contains(github.ref_name, '-alpha.') || contains(github.ref_name, '-beta.') }}\n        files: |\n          *.tar.gz\n          *.zip\n        fail_on_unmatched_files: ${{ needs.check.outputs.targets != '' }}\n        generate_release_notes: true\n        append_body: true\n\n# based on: github.com/koron-go/_skeleton/.github/workflows/go.yml\n# $Hash:01f9cf8649094e7b57bcfa7103802dcd6953b81d214480fccdfdfbc4$\n"
  },
  {
    "path": ".gitignore",
    "content": "/tags\n/tmp/\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 MURAOKA Taro <koron.kaoriya@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "# Get relative paths of all \"main\" packages\nMAIN_PACKAGE ?= $(shell go list -f '{{if (eq .Name \"main\")}}.{{slice .ImportPath (len .Module.Path)}}{{end}}' ./...)\n\nTEST_PACKAGE ?= ./...\n\n.PHONY: build\nbuild:\n\tgo build -gcflags '-e' ./...\n\n.PHONY: test\ntest:\n\tgo test $(TEST_PACKAGE)\n\n.PHONY: race\nrace:\n\tgo test -race $(TEST_PACKAGE)\n\n.PHONY: bench\nbench:\n\tgo test -bench $(TEST_PACKAGE)\n\n.PHONY: tags\ntags:\n\tgotags -f tags -R .\n\n.PHONY: cover\ncover:\n\tmkdir -p tmp\n\tgo test -coverprofile tmp/_cover.out $(TEST_PACKAGE)\n\tgo tool cover -html tmp/_cover.out -o tmp/cover.html\n\n.PHONY: checkall\ncheckall: vet staticcheck\n\n.PHONY: vet\nvet:\n\tgo vet $(TEST_PACKAGE)\n\n.PHONY: staticcheck\nstaticcheck:\n\tstaticcheck $(TEST_PACKAGE)\n\n.PHONY: clean\nclean:\n\tgo clean\n\trm -f tags\n\trm -f tmp/_cover.out tmp/cover.html\n\n.PHONY: upgradable\nupgradable:\n\t@go list -m -mod=readonly -u -f='{{if and (not .Indirect) (not .Main)}}{{if .Update}}{{.Path}}@{{.Update.Version}} [{{.Version}}]{{else if .Replace}}{{if .Replace.Update}}{{.Path}}@{{.Replace.Update.Version}} [replaced:{{.Replace.Version}} {{.Version}}]{{end}}{{end}}{{end}}' all\n\n.PHONY: upgradable-all\nupgradable-all:\n\t@go list -m -u -f '{{if .Update}}{{.Path}} {{.Version}} [{{.Update.Version}}]{{end}}' all\n\n# Build all \"main\" packages\n.PHONY: main-build\nmain-build:\n\t@for d in $(MAIN_PACKAGE) ; do \\\n\t  echo \"cd $$d && go build -gcflags '-e'\" ; \\\n\t  ( cd $$d && go build -gcflags '-e' ) ; \\\n\tdone\n\n# Clean all \"main\" packages\n.PHONY: main-clean\nmain-clean:\n\t@for d in $(MAIN_PACKAGE) ; do \\\n\t  echo \"cd $$d && go clean\" ; \\\n\t  ( cd $$d && go clean ) ; \\\n\tdone\n\n# based on: github.com/koron-go/_skeleton/Makefile\n# $Hash:93a5966a0297543bcdd82a4dd9c2d60232a1b02c49cfa0b4341fdb71$\n"
  },
  {
    "path": "README.md",
    "content": "# dProxy - document proxy\n\n[![GoDoc](https://godoc.org/github.com/koron/go-dproxy?status.svg)](https://godoc.org/github.com/koron/go-dproxy)\n[![Actions/Go](https://github.com/koron/go-dproxy/workflows/Go/badge.svg)](https://github.com/koron/go-dproxy/actions?query=workflow%3AGo)\n[![Go Report Card](https://goreportcard.com/badge/github.com/koron/go-dproxy)](https://goreportcard.com/report/github.com/koron/go-dproxy)\n\ndProxy is a proxy to access `interface{}` (document) by simple query.\nIt is intented to be used with `json.Unmarshal()` or `json.NewDecorder()`.\n\nSee codes for overview.\n\n```go\nimport (\n  \"encoding/json\"\n\n  \"github.com/koron/go-dproxy\"\n)\n\nvar v interface{}\njson.Unmarshal([]byte(`{\n  \"cities\": [ \"tokyo\", 100, \"osaka\", 200, \"hakata\", 300 ],\n  \"data\": {\n    \"custom\": [ \"male\", 23, \"female\", 24 ]\n  }\n}`), &v)\n\n// s == \"tokyo\", got a string.\ns, _ := dproxy.New(v).M(\"cities\").A(0).String()\n\n// err != nil, type not matched.\n_, err := dproxy.New(v).M(\"cities\").A(0).Float64()\n\n// n == 200, got a float64\nn, _ := dproxy.New(v).M(\"cities\").A(3).Float64()\n\n// can be chained.\ndproxy.New(v).M(\"data\").M(\"custom\").A(0).String()\n\n// err.Error() == \"not found: data.kustom\", wrong query can be verified.\n_, err = dproxy.New(v).M(\"data\").M(\"kustom\").String()\n```\n\n\n## Getting started\n\n### Proxy\n\n1.  Wrap a value (`interface{}`) with `dproxy.New()` get `dproxy.Proxy`.\n\n    ```go\n    p := dproxy.New(v) // v should be a value of interface{}\n    ```\n\n2.  Query as a map (`map[string]interface{}`)by `M()`, returns `dproxy.Proxy`.\n\n    ```go\n    p.M(\"cities\")\n    ```\n\n3.  Query as an array (`[]interface{}`) with `A()`, returns `dproxy.Proxy`.\n\n    ```go\n    p.A(3)\n    ```\n\n4.  Therefore, can be chained queries.\n\n    ```go\n    p.M(\"cities\").A(3)\n    ```\n\n5.  Get a value finally.\n\n    ```go\n    n, _ := p.M(\"cities\").A(3).Int64()\n    ```\n\n6.  You'll get an error when getting a value, if there were some mistakes.\n\n    ```go\n    // OOPS! \"kustom\" is typo, must be \"custom\"\n    _, err := p.M(\"data\").M(\"kustom\").A(3).Int64()\n\n    // \"not found: data.kustom\"\n    fmt.Println(err)\n    ```\n\n7.  If you tried to get a value as different type, get an error.\n\n    ```go\n    // OOPS! \"cities[3]\" (=200) should be float64 or int64.\n    _, err := p.M(\"cities\").A(3).String()\n\n    // \"not matched types: expected=string actual=float64: cities[3]\"\n    fmt.Println(err)\n    ```\n\n8.  You can verify queries easily.\n\n### Drain\n\nGetting value and error from Proxy/ProxySet multiple times, is very awful.\nIt must check error when every getting values.\n\n```go\np := dproxy.New(v)\nv1, err := p.M(\"cities\").A(3).Int64()\nif err != nil {\n    return err\n}\nv2, err := p.M(\"data\").M(\"kustom\").A(3).Int64()\nif err != nil {\n    return err\n}\nv3, err := p.M(\"cities\").A(3).String()\nif err != nil {\n    return err\n}\n```\n\nIt can be rewrite as simple like below with `dproxy.Drain`\n\n```go\nvar d Drain\np := dproxy.New(v)\nv1 := d.Int64(p.M(\"cities\").A(3))\nv2 := d.Int64(p.M(\"data\").M(\"kustom\").A(3))\nv3 := d.String(p.M(\"cities\").A(3))\nif err := d.CombineErrors(); err != nil {\n    return err\n}\n```\n\n### JSON Pointer\n\nJSON Pointer can be used to query `interface{}`\n\n```go\nv1, err := dproxy.New(v).P(\"/cities/0\").Int64()\n```\n\nor\n\n```go\nv1, err := dproxy.Pointer(v, \"/cities/0\").Int64()\n```\n\nSee [RFC6901][1] for details of JSON Pointer.\n\n\n## LICENSE\n\nMIT license.  See LICENSE.\n\n[1]: https://tools.ietf.org/html/rfc6901\n"
  },
  {
    "path": "doc.go",
    "content": "/*\nPackage dproxy provides a proxy to adccess `interface{}` (document) by simple\nquery.  It is intended to be used with `\"encoding/json\".Unmarshal()` or so.\n*/\npackage dproxy\n"
  },
  {
    "path": "drain.go",
    "content": "package dproxy\n\nimport \"bytes\"\n\n// Drain stores errors from Proxy or ProxySet.\ntype Drain struct {\n\terrors []error\n}\n\n// Has returns true if the drain stored some of errors.\nfunc (d *Drain) Has() bool {\n\treturn d != nil && len(d.errors) > 0\n}\n\n// First returns a stored error.  Returns nil if there are no errors.\nfunc (d *Drain) First() error {\n\tif d == nil || len(d.errors) == 0 {\n\t\treturn nil\n\t}\n\treturn d.errors[0]\n}\n\n// All returns all errors which stored.  Return nil if no errors stored.\nfunc (d *Drain) All() []error {\n\tif d == nil || len(d.errors) == 0 {\n\t\treturn nil\n\t}\n\ta := make([]error, 0, len(d.errors))\n\treturn append(a, d.errors...)\n}\n\n// CombineErrors returns an error which combined all stored errors.  Return nil\n// if not erros stored.\nfunc (d *Drain) CombineErrors() error {\n\tif d == nil || len(d.errors) == 0 {\n\t\treturn nil\n\t}\n\treturn drainError(d.errors)\n}\n\nfunc (d *Drain) put(err error) {\n\tif err == nil {\n\t\treturn\n\t}\n\td.errors = append(d.errors, err)\n}\n\n// Bool returns bool value and stores an error.\nfunc (d *Drain) Bool(p Proxy) bool {\n\tv, err := p.Bool()\n\td.put(err)\n\treturn v\n}\n\n// Int64 returns int64 value and stores an error.\nfunc (d *Drain) Int64(p Proxy) int64 {\n\tv, err := p.Int64()\n\td.put(err)\n\treturn v\n}\n\n// Float64 returns float64 value and stores an error.\nfunc (d *Drain) Float64(p Proxy) float64 {\n\tv, err := p.Float64()\n\td.put(err)\n\treturn v\n}\n\n// String returns string value and stores an error.\nfunc (d *Drain) String(p Proxy) string {\n\tv, err := p.String()\n\td.put(err)\n\treturn v\n}\n\n// Array returns []interface{} value and stores an error.\nfunc (d *Drain) Array(p Proxy) []interface{} {\n\tv, err := p.Array()\n\td.put(err)\n\treturn v\n}\n\n// Map returns map[string]interface{} value and stores an error.\nfunc (d *Drain) Map(p Proxy) map[string]interface{} {\n\tv, err := p.Map()\n\td.put(err)\n\treturn v\n}\n\n// BoolArray returns []bool value and stores an error.\nfunc (d *Drain) BoolArray(ps ProxySet) []bool {\n\tv, err := ps.BoolArray()\n\td.put(err)\n\treturn v\n}\n\n// Int64Array returns []int64 value and stores an error.\nfunc (d *Drain) Int64Array(ps ProxySet) []int64 {\n\tv, err := ps.Int64Array()\n\td.put(err)\n\treturn v\n}\n\n// Float64Array returns []float64 value and stores an error.\nfunc (d *Drain) Float64Array(ps ProxySet) []float64 {\n\tv, err := ps.Float64Array()\n\td.put(err)\n\treturn v\n}\n\n// StringArray returns []string value and stores an error.\nfunc (d *Drain) StringArray(ps ProxySet) []string {\n\tv, err := ps.StringArray()\n\td.put(err)\n\treturn v\n}\n\n// ArrayArray returns [][]interface{} value and stores an error.\nfunc (d *Drain) ArrayArray(ps ProxySet) [][]interface{} {\n\tv, err := ps.ArrayArray()\n\td.put(err)\n\treturn v\n}\n\n// MapArray returns []map[string]interface{} value and stores an error.\nfunc (d *Drain) MapArray(ps ProxySet) []map[string]interface{} {\n\tv, err := ps.MapArray()\n\td.put(err)\n\treturn v\n}\n\n// ProxyArray returns []Proxy value and stores an error.\nfunc (d *Drain) ProxyArray(ps ProxySet) []Proxy {\n\tv, err := ps.ProxyArray()\n\td.put(err)\n\treturn v\n}\n\ntype drainError []error\n\nfunc (derr drainError) Error() string {\n\tb := bytes.Buffer{}\n\tfor i, err := range derr {\n\t\tif i > 0 {\n\t\t\t_, _ = b.WriteString(\"; \")\n\t\t}\n\t\t_, _ = b.WriteString(err.Error())\n\t}\n\treturn b.String()\n}\n"
  },
  {
    "path": "drain_test.go",
    "content": "package dproxy\n\nimport (\n\t\"testing\"\n)\n\nfunc TestDrainBool(t *testing.T) {\n\tv := parseJSON(`{\n\t\t\"foo\": true,\n\t\t\"bar\": false\n\t}`)\n\n\td := new(Drain)\n\n\tfoo := d.Bool(New(v).M(\"foo\"))\n\tif d.Has() {\n\t\tt.Error(d.First())\n\t} else if foo != true {\n\t\tt.Errorf(\"foo must be true\")\n\t}\n\n\tbar := d.Bool(New(v).M(\"bar\"))\n\tif d.Has() {\n\t\tt.Error(d.First())\n\t} else if bar != false {\n\t\tt.Errorf(\"bar must be false\")\n\t}\n\n\tbaz := d.Bool(New(v).M(\"baz\"))\n\tif !d.Has() {\n\t\tt.Error(\"baz must not exist\")\n\t} else if err := d.First(); err == nil || err.Error() != \"not found: baz\" {\n\t\tt.Errorf(\"unexpected error: %s\", err)\n\t}\n\t_ = baz\n}\n"
  },
  {
    "path": "error.go",
    "content": "package dproxy\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\n// ErrorType is type of errors\ntype ErrorType int\n\nconst (\n\t// Etype means expected type is not matched with actual.\n\tEtype ErrorType = iota + 1\n\n\t// Enotfound means key or index doesn't exist.\n\tEnotfound\n\n\t// EmapNorArray means target is not a map nor an array (for JSON Pointer)\n\tEmapNorArray\n\n\t// EconvertFailure means value conversion is failed.\n\tEconvertFailure\n\n\t// EinvalidIndex means token is invalid as index (for JSON Pointer)\n\tEinvalidIndex\n\n\t// EinvalidQuery means query is invalid as JSON Pointer.\n\tEinvalidQuery\n\n\t// ErequiredType means the type mismatch against user required one.\n\t// For example M() requires map, A() requires array.\n\tErequiredType\n)\n\nfunc (et ErrorType) String() string {\n\tswitch et {\n\tcase Etype:\n\t\treturn \"Etype\"\n\tcase Enotfound:\n\t\treturn \"Enotfound\"\n\tcase EmapNorArray:\n\t\treturn \"EmapNorArray\"\n\tcase EconvertFailure:\n\t\treturn \"EconvertFailure\"\n\tcase EinvalidIndex:\n\t\treturn \"EinvalidIndex\"\n\tcase EinvalidQuery:\n\t\treturn \"EinvalidQuery\"\n\tcase ErequiredType:\n\t\treturn \"ErequiredType\"\n\tdefault:\n\t\treturn \"Eunknown\"\n\t}\n}\n\n// Error get detail information of the errror.\ntype Error interface {\n\t// ErrorType returns type of error.\n\tErrorType() ErrorType\n\n\t// FullAddress returns query string where cause first error.\n\tFullAddress() string\n}\n\ntype errorProxy struct {\n\terrorType ErrorType\n\tparent    frame\n\tlabel     string\n\n\texpected Type\n\tactual   Type\n\tinfoStr  string\n}\n\n// errorProxy implements error, Proxy and ProxySet.\nvar (\n\t_ error    = (*errorProxy)(nil)\n\t_ Proxy    = (*errorProxy)(nil)\n\t_ ProxySet = (*errorProxy)(nil)\n)\n\nfunc (p *errorProxy) Nil() bool {\n\treturn false\n}\n\nfunc (p *errorProxy) Value() (interface{}, error) {\n\treturn nil, p\n}\n\nfunc (p *errorProxy) Bool() (bool, error) {\n\treturn false, p\n}\n\nfunc (p *errorProxy) Int64() (int64, error) {\n\treturn 0, p\n}\n\nfunc (p *errorProxy) Float64() (float64, error) {\n\treturn 0, p\n}\n\nfunc (p *errorProxy) String() (string, error) {\n\treturn \"\", p\n}\n\nfunc (p *errorProxy) Array() ([]interface{}, error) {\n\treturn nil, p\n}\n\nfunc (p *errorProxy) Map() (map[string]interface{}, error) {\n\treturn nil, p\n}\n\nfunc (p *errorProxy) A(n int) Proxy {\n\treturn p\n}\n\nfunc (p *errorProxy) M(k string) Proxy {\n\treturn p\n}\n\nfunc (p *errorProxy) P(q string) Proxy {\n\treturn p\n}\n\nfunc (p *errorProxy) Empty() bool {\n\treturn true\n}\n\nfunc (p *errorProxy) Len() int {\n\treturn 0\n}\n\nfunc (p *errorProxy) BoolArray() ([]bool, error) {\n\treturn nil, p\n}\n\nfunc (p *errorProxy) Int64Array() ([]int64, error) {\n\treturn nil, p\n}\n\nfunc (p *errorProxy) Float64Array() ([]float64, error) {\n\treturn nil, p\n}\n\nfunc (p *errorProxy) StringArray() ([]string, error) {\n\treturn nil, p\n}\n\nfunc (p *errorProxy) ArrayArray() ([][]interface{}, error) {\n\treturn nil, p\n}\n\nfunc (p *errorProxy) MapArray() ([]map[string]interface{}, error) {\n\treturn nil, p\n}\n\nfunc (p *errorProxy) ProxyArray() ([]Proxy, error) {\n\treturn nil, p\n}\n\nfunc (p *errorProxy) ProxySet() ProxySet {\n\treturn p\n}\n\nfunc (p *errorProxy) Q(k string) ProxySet {\n\treturn p\n}\n\nfunc (p *errorProxy) Qc(k string) ProxySet {\n\treturn p\n}\n\nfunc (p *errorProxy) findJPT(t string) Proxy {\n\treturn p\n}\n\nfunc (p *errorProxy) parentFrame() frame {\n\treturn p.parent\n}\n\nfunc (p *errorProxy) frameLabel() string {\n\treturn p.label\n}\n\nfunc (p *errorProxy) Error() string {\n\tswitch p.errorType {\n\tcase Etype:\n\t\treturn fmt.Sprintf(\"not matched types: expected=%s actual=%s: %s\",\n\t\t\tp.expected.String(), p.actual.String(), p.FullAddress())\n\tcase Enotfound:\n\t\treturn fmt.Sprintf(\"not found: %s\", p.FullAddress())\n\tcase EmapNorArray:\n\t\t// FIXME: better error message.\n\t\treturn fmt.Sprintf(\"not map nor array: actual=%s: %s\",\n\t\t\tp.actual.String(), p.FullAddress())\n\tcase EconvertFailure:\n\t\treturn fmt.Sprintf(\"convert error: %s: %s\", p.infoStr, p.FullAddress())\n\tcase EinvalidIndex:\n\t\t// FIXME: better error message.\n\t\treturn fmt.Sprintf(\"invalid index: %s: %s\", p.infoStr, p.FullAddress())\n\tcase EinvalidQuery:\n\t\t// FIXME: better error message.\n\t\treturn fmt.Sprintf(\"invalid query: %s: %s\", p.infoStr, p.FullAddress())\n\tcase ErequiredType:\n\t\treturn fmt.Sprintf(\"not required types: required=%s actual=%s: %s\",\n\t\t\tp.expected.String(), p.actual.String(), p.FullAddress())\n\tdefault:\n\t\treturn fmt.Sprintf(\"unexpected: %s\", p.FullAddress())\n\t}\n}\n\nfunc (p *errorProxy) ErrorType() ErrorType {\n\treturn p.errorType\n}\n\nfunc (p *errorProxy) FullAddress() string {\n\treturn fullAddress(p)\n}\n\nfunc typeError(p frame, expected Type, actual interface{}) *errorProxy {\n\treturn &errorProxy{\n\t\terrorType: Etype,\n\t\tparent:    p,\n\t\texpected:  expected,\n\t\tactual:    detectType(actual),\n\t}\n}\n\nfunc requiredTypeError(p frame, expected Type, actual interface{}) *errorProxy {\n\treturn &errorProxy{\n\t\terrorType: ErequiredType,\n\t\tparent:    p,\n\t\texpected:  expected,\n\t\tactual:    detectType(actual),\n\t}\n}\n\nfunc elementTypeError(p frame, index int, expected Type, actual interface{}) *errorProxy {\n\tq := &simpleFrame{\n\t\tparent: p,\n\t\tlabel:  \"[\" + strconv.Itoa(index) + \"]\",\n\t}\n\treturn typeError(q, expected, actual)\n}\n\nfunc notfoundError(p frame, address string) *errorProxy {\n\treturn &errorProxy{\n\t\terrorType: Enotfound,\n\t\tparent:    p,\n\t\tlabel:     address,\n\t}\n}\n"
  },
  {
    "path": "frame.go",
    "content": "package dproxy\n\ntype frame interface {\n\t// parentFrame returns parent frame.\n\tparentFrame() frame\n\t// frameLabel return label of frame.\n\tframeLabel() string\n}\n\nfunc fullAddress(f frame) string {\n\tx := 0\n\tfor g := f; g != nil; g = g.parentFrame() {\n\t\tx += len(g.frameLabel())\n\t}\n\tif x == 0 {\n\t\treturn \"(root)\"\n\t}\n\tb := make([]byte, x)\n\tfor g := f; g != nil; g = g.parentFrame() {\n\t\tx -= len(g.frameLabel())\n\t\tcopy(b[x:], g.frameLabel())\n\t}\n\tif b[0] == '.' {\n\t\treturn string(b[1:])\n\t}\n\treturn string(b)\n}\n\ntype simpleFrame struct {\n\tparent frame\n\tlabel  string\n}\n\nvar _ frame = (*simpleFrame)(nil)\n\nfunc (f *simpleFrame) parentFrame() frame {\n\treturn f.parent\n}\n\nfunc (f *simpleFrame) frameLabel() string {\n\treturn f.label\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/koron/go-dproxy\n\ngo 1.13\n"
  },
  {
    "path": "go.sum",
    "content": ""
  },
  {
    "path": "package_test.go",
    "content": "package dproxy\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc assertEquals(t *testing.T, actual, expected interface{}, format string, a ...interface{}) {\n\tt.Helper()\n\tif !reflect.DeepEqual(actual, expected) {\n\t\tmsg := fmt.Sprintf(format, a...)\n\t\tt.Errorf(\"not equal: %s\\nexpect=%+v\\nactual=%+v\", msg, expected, actual)\n\t}\n}\n\nfunc assertError(t *testing.T, err error, exp string) {\n\tt.Helper()\n\tif err == nil {\n\t\tt.Fatalf(\"should fail with: %s\", exp)\n\t}\n\tif act := err.Error(); act != exp {\n\t\tt.Fatalf(\"unexpected error:\\nexpect=%s\\nactual=%s\\n\", exp, act)\n\t}\n}\n"
  },
  {
    "path": "pointer.go",
    "content": "package dproxy\n\nimport \"strings\"\n\nvar jptR = strings.NewReplacer(\"~1\", \"/\", \"~0\", \"~\")\n\nfunc unescapeJPT(t string) string {\n\treturn jptR.Replace(t)\n}\n\nfunc pointer(p Proxy, q string) Proxy {\n\tif len(q) == 0 {\n\t\treturn p\n\t}\n\tif q[0] != '/' {\n\t\treturn &errorProxy{\n\t\t\terrorType: EinvalidQuery,\n\t\t\tparent:    p,\n\t\t\tinfoStr:   \"not start with '/'\",\n\t\t}\n\t}\n\tfor _, t := range strings.Split(q[1:], \"/\") {\n\t\tp = p.findJPT(unescapeJPT(t))\n\t}\n\treturn p\n}\n\n// Pointer returns a Proxy which pointed by JSON Pointer's query q\nfunc Pointer(v interface{}, q string) Proxy {\n\treturn pointer(New(v), q)\n}\n"
  },
  {
    "path": "pointer_test.go",
    "content": "package dproxy\n\nimport \"testing\"\n\nfunc TestUnescapeJPT(t *testing.T) {\n\tf := func(d, expect string) {\n\t\ts := unescapeJPT(d)\n\t\tif s != expect {\n\t\t\tt.Errorf(\"unescapeJPT(%q) should be %q but actually %q\", d, expect, s)\n\t\t}\n\t}\n\tf(\"foo\", \"foo\")\n\tf(\"bar\", \"bar\")\n\tf(\"~0\", \"~\")\n\tf(\"foo~0bar\", \"foo~bar\")\n\tf(\"~1\", \"/\")\n\tf(\"foo~1bar\", \"foo/bar\")\n\tf(\"~01\", \"~1\")\n\tf(\"foo~01bar\", \"foo~1bar\")\n\tf(\"~10\", \"/0\")\n}\n\nfunc TestPointerInvalidQuery(t *testing.T) {\n\tp := Pointer(nil, \"invalid\")\n\terr, ok := p.(*errorProxy)\n\tif !ok {\n\t\tt.Fatalf(\"it should be *errorProxy but: %+v\", p)\n\t}\n\tif err.errorType != EinvalidQuery {\n\t\tt.Fatalf(\"errorType should be EinvalidQuery but: %s\", err.errorType)\n\t}\n}\n\nfunc TestPointer(t *testing.T) {\n\tf := func(q string, d, expected interface{}) {\n\t\tp := Pointer(d, q)\n\t\tv, err := p.Value()\n\t\tif err != nil {\n\t\t\tt.Errorf(\"Pointer:%q for %+v failed: %s\", q, d, err)\n\t\t\treturn\n\t\t}\n\t\tassertEquals(t, v, expected, \"Pointer:%q for %+v\", q, d)\n\t}\n\n\tv := parseJSON(`{\n\t\t\"cities\": [ \"tokyo\", 100, \"osaka\", 200, \"hakata\", 300 ],\n\t\t\"data\": {\n\t\t\t\"custom\": [ \"male\", 21, \"female\", 22 ]\n\t\t}\n\t}`)\n\tf(\"\", v, v)\n\tf(\"/cities\", v, parseJSON(`[\"tokyo\",100,\"osaka\",200,\"hakata\",300]`))\n\tf(\"/cities/0\", v, \"tokyo\")\n\tf(\"/cities/1\", v, float64(100))\n\tf(\"/cities/2\", v, \"osaka\")\n\tf(\"/cities/3\", v, float64(200))\n\tf(\"/cities/4\", v, \"hakata\")\n\tf(\"/cities/5\", v, float64(300))\n\tf(\"/data/custom\", v, parseJSON(`[\"male\",21,\"female\",22]`))\n\n\t// Example from RFC6901 https://tools.ietf.org/html/rfc6901\n\tw := parseJSON(`{\n\t\t\"foo\": [\"bar\", \"baz\"],\n\t\t\"\": 0,\n\t\t\"a/b\": 1,\n\t\t\"c%d\": 2,\n\t\t\"e^f\": 3,\n\t\t\"g|h\": 4,\n\t\t\"i\\\\j\": 5,\n\t\t\"k\\\"l\": 6,\n\t\t\" \": 7,\n\t\t\"m~n\": 8\n\t}`)\n\tf(\"\", w, w)\n\tf(\"/foo\", w, parseJSON(`[\"bar\",\"baz\"]`))\n\tf(\"/foo/0\", w, \"bar\")\n\tf(\"/\", w, float64(0))\n\tf(\"/a~1b\", w, float64(1))\n\tf(\"/c%d\", w, float64(2))\n\tf(\"/e^f\", w, float64(3))\n\tf(\"/g|h\", w, float64(4))\n\tf(\"/i\\\\j\", w, float64(5))\n\tf(\"/k\\\"l\", w, float64(6))\n\tf(\"/ \", w, float64(7))\n\tf(\"/m~0n\", w, float64(8))\n}\n"
  },
  {
    "path": "proxy.go",
    "content": "package dproxy\n\n// Proxy is a proxy to access a document (interface{}).\ntype Proxy interface {\n\t// Nil returns true, if target value is nil.\n\tNil() bool\n\n\t// Value returns a proxied value.  If there are no values, it returns\n\t// error.\n\tValue() (interface{}, error)\n\n\t// Bool returns its value.  If value isn't the type, it returns error.\n\tBool() (bool, error)\n\n\t// Int64 returns its value.  If value isn't the type, it returns error.\n\tInt64() (int64, error)\n\n\t// Float64 returns its value.  If value isn't the type, it returns error.\n\tFloat64() (float64, error)\n\n\t// String returns its value.  If value isn't the type, it returns error.\n\tString() (string, error)\n\n\t// Array returns its value.  If value isn't the type, it returns error.\n\tArray() ([]interface{}, error)\n\n\t// Map returns its value.  If value isn't the type, it returns error.\n\tMap() (map[string]interface{}, error)\n\n\t// A returns an item from value treated as the array.\n\tA(n int) Proxy\n\n\t// M returns an item from value treated as the map.\n\tM(k string) Proxy\n\n\t// P returns which pointed by JSON Pointer's query q.\n\tP(q string) Proxy\n\n\t// ProxySet returns a set which converted from its array value.\n\tProxySet() ProxySet\n\n\t// Q returns set of all items which property matchs with k.\n\tQ(k string) ProxySet\n\n\t// findJPT returns a match of JSON Pointer's Token t.\n\tfindJPT(t string) Proxy\n\n\t// Proxy implements frame.\n\tframe\n}\n\n// ProxySet proxies to access to set.\ntype ProxySet interface {\n\t// Empty returns true when the set is empty.\n\tEmpty() bool\n\n\t// Len returns count of items in the set.\n\tLen() int\n\n\t// BoolArray returns []bool which converterd from the set.\n\tBoolArray() ([]bool, error)\n\n\t// Int64Array returns []int64 which converterd from the set.\n\tInt64Array() ([]int64, error)\n\n\t// Float64Array returns []float64 which converterd from the set.\n\tFloat64Array() ([]float64, error)\n\n\t// StringArray returns []string which converterd from the set.\n\tStringArray() ([]string, error)\n\n\t// ArrayArray returns [][]interface{} which converterd from the set.\n\tArrayArray() ([][]interface{}, error)\n\n\t// MapArray returns []map[string]interface{} which converterd from the set.\n\tMapArray() ([]map[string]interface{}, error)\n\n\t// ProxyArray returns []Proxy which wrap each items.\n\tProxyArray() ([]Proxy, error)\n\n\t// A returns an proxy for index in the set.\n\tA(n int) Proxy\n\n\t// Q returns set of all items which property matchs with k.\n\tQ(k string) ProxySet\n\n\t// Qc returns set of property of all items.\n\tQc(k string) ProxySet\n\n\t// Proxy implements frame.\n\tframe\n}\n\n// New creates a new Proxy instance for v.\nfunc New(v interface{}) Proxy {\n\treturn &valueProxy{value: v}\n}\n\n// NewSet create a new ProxySet instance for v.\nfunc NewSet(v []interface{}) ProxySet {\n\treturn &setProxy{values: v}\n}\n"
  },
  {
    "path": "proxy_test.go",
    "content": "package dproxy\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n)\n\nfunc parseJSON(s string) interface{} {\n\tvar v interface{}\n\tif err := json.Unmarshal([]byte(s), &v); err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\nfunc equalStrings(a, b []string) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor i, s := range a {\n\t\tif s != b[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc equalInts(a, b []int64) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor i, s := range a {\n\t\tif s != b[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc TestReadme(t *testing.T) {\n\tv := parseJSON(`{\n\t\t\"cities\": [ \"tokyo\", 100, \"osaka\", 200, \"hakata\", 300 ],\n\t\t\"data\": {\n\t\t\t\"custom\": [ \"male\", 21, \"female\", 22 ]\n\t\t}\n\t}`)\n\n\ts, err := New(v).M(\"cities\").A(0).String()\n\tif s != \"tokyo\" {\n\t\tt.Error(\"cities[0] must be \\\"tokyo\\\":\", err)\n\t}\n\n\t_, err = New(v).M(\"cities\").A(0).Float64()\n\tif err == nil {\n\t\tt.Error(\"cities[0] (float64) must be failed:\", err)\n\t}\n\n\tn, err := New(v).M(\"cities\").A(1).Float64()\n\tif n != 100 {\n\t\tt.Error(\"cities[1] must be 100:\", err)\n\t}\n\n\ts2, err := New(v).M(\"data\").M(\"custom\").A(2).String()\n\tif s2 != \"female\" {\n\t\tt.Error(\"data.custom[2] must be \\\"female\\\":\", err)\n\t}\n\n\t_, err = New(v).M(\"data\").M(\"kustom\").String()\n\tif err == nil || err.Error() != \"not found: data.kustom\" {\n\t\tt.Error(\"err is not \\\"not found: data.kustom\\\":\", err)\n\t}\n}\n\nfunc TestMapBool(t *testing.T) {\n\tv := parseJSON(`{\n\t\t\"foo\": true,\n\t\t\"bar\": false\n\t}`)\n\n\t// check \"foo\"\n\tfoo, err := New(v).M(\"foo\").Bool()\n\tif err != nil {\n\t\tt.Error(err)\n\t} else if foo != true {\n\t\tt.Errorf(\"foo must be true\")\n\t}\n\n\t// check \"bar\"\n\tbar, err := New(v).M(\"bar\").Bool()\n\tif err != nil {\n\t\tt.Error(err)\n\t} else if bar != false {\n\t\tt.Errorf(\"bar must be false\")\n\t}\n}\n\ntype wrappedMap map[string]interface{}\n\nfunc TestWrappedMap(t *testing.T) {\n\tv := wrappedMap{\n\t\t\"foo\": 123,\n\t}\n\tn, err := New(v).M(\"foo\").Int64()\n\tif err != nil {\n\t\tt.Fatalf(\"failed: %s\", err)\n\t}\n\tif n != 123 {\n\t\tt.Fatalf(\"unexpected value: %d\", n)\n\t}\n}\n"
  },
  {
    "path": "set.go",
    "content": "package dproxy\n\nimport \"strconv\"\n\ntype setProxy struct {\n\tvalues []interface{}\n\tparent frame\n\tlabel  string\n}\n\n// setProxy implements ProxySet\nvar _ ProxySet = (*setProxy)(nil)\n\nfunc (p *setProxy) Empty() bool {\n\treturn p.Len() == 0\n}\n\nfunc (p *setProxy) Len() int {\n\treturn len(p.values)\n}\n\nfunc (p *setProxy) BoolArray() ([]bool, error) {\n\tr := make([]bool, len(p.values))\n\tfor i, v := range p.values {\n\t\tswitch v := v.(type) {\n\t\tcase bool:\n\t\t\tr[i] = v\n\t\tdefault:\n\t\t\treturn nil, elementTypeError(p, i, Tbool, v)\n\t\t}\n\t}\n\treturn r, nil\n}\n\nfunc (p *setProxy) Int64Array() ([]int64, error) {\n\tr := make([]int64, len(p.values))\n\tfor i, v := range p.values {\n\t\tswitch v := v.(type) {\n\t\tcase int:\n\t\t\tr[i] = int64(v)\n\t\tcase int32:\n\t\t\tr[i] = int64(v)\n\t\tcase int64:\n\t\t\tr[i] = v\n\t\tcase float32:\n\t\t\tr[i] = int64(v)\n\t\tcase float64:\n\t\t\tr[i] = int64(v)\n\t\tdefault:\n\t\t\treturn nil, elementTypeError(p, i, Tint64, v)\n\t\t}\n\t}\n\treturn r, nil\n}\n\nfunc (p *setProxy) Float64Array() ([]float64, error) {\n\tr := make([]float64, len(p.values))\n\tfor i, v := range p.values {\n\t\tswitch v := v.(type) {\n\t\tcase int:\n\t\t\tr[i] = float64(v)\n\t\tcase int32:\n\t\t\tr[i] = float64(v)\n\t\tcase int64:\n\t\t\tr[i] = float64(v)\n\t\tcase float32:\n\t\t\tr[i] = float64(v)\n\t\tcase float64:\n\t\t\tr[i] = v\n\t\tdefault:\n\t\t\treturn nil, elementTypeError(p, i, Tfloat64, v)\n\t\t}\n\t}\n\treturn r, nil\n}\n\nfunc (p *setProxy) StringArray() ([]string, error) {\n\tr := make([]string, len(p.values))\n\tfor i, v := range p.values {\n\t\tswitch v := v.(type) {\n\t\tcase string:\n\t\t\tr[i] = v\n\t\tdefault:\n\t\t\treturn nil, elementTypeError(p, i, Tstring, v)\n\t\t}\n\t}\n\treturn r, nil\n}\n\nfunc (p *setProxy) ArrayArray() ([][]interface{}, error) {\n\tr := make([][]interface{}, len(p.values))\n\tfor i, v := range p.values {\n\t\tswitch v := v.(type) {\n\t\tcase []interface{}:\n\t\t\tr[i] = v\n\t\tdefault:\n\t\t\treturn nil, elementTypeError(p, i, Tarray, v)\n\t\t}\n\t}\n\treturn r, nil\n}\n\nfunc (p *setProxy) MapArray() ([]map[string]interface{}, error) {\n\tr := make([]map[string]interface{}, len(p.values))\n\tfor i, v := range p.values {\n\t\tswitch v := v.(type) {\n\t\tcase map[string]interface{}:\n\t\t\tr[i] = v\n\t\tdefault:\n\t\t\treturn nil, elementTypeError(p, i, Tmap, v)\n\t\t}\n\t}\n\treturn r, nil\n}\n\nfunc (p *setProxy) ProxyArray() ([]Proxy, error) {\n\tr := make([]Proxy, 0, len(p.values))\n\tfor i, v := range p.values {\n\t\tr = append(r, &valueProxy{\n\t\t\tvalue:  v,\n\t\t\tparent: p,\n\t\t\tlabel:  \"[\" + strconv.Itoa(i) + \"]\",\n\t\t})\n\t}\n\treturn r, nil\n}\n\nfunc (p *setProxy) A(n int) Proxy {\n\ta := \"[\" + strconv.Itoa(n) + \"]\"\n\tif n < 0 || n >= len(p.values) {\n\t\treturn notfoundError(p, a)\n\t}\n\treturn &valueProxy{\n\t\tvalue:  p.values[n],\n\t\tparent: p,\n\t\tlabel:  a,\n\t}\n}\n\nfunc (p *setProxy) Q(k string) ProxySet {\n\tw := findAll(p.values, k)\n\treturn &setProxy{\n\t\tvalues: w,\n\t\tparent: p,\n\t\tlabel:  \"..\" + k,\n\t}\n}\n\nfunc (p *setProxy) Qc(k string) ProxySet {\n\tr := make([]interface{}, 0, len(p.values))\n\tfor _, v := range p.values {\n\t\tswitch v := v.(type) {\n\t\tcase map[string]interface{}:\n\t\t\tif w, ok := v[k]; ok {\n\t\t\t\tr = append(r, w)\n\t\t\t}\n\t\t}\n\t}\n\treturn &setProxy{\n\t\tvalues: r,\n\t\tparent: p,\n\t\tlabel:  \"..\" + k,\n\t}\n}\n\nfunc (p *setProxy) parentFrame() frame {\n\treturn p.parent\n}\n\nfunc (p *setProxy) frameLabel() string {\n\treturn p.label\n}\n\nfunc findAll(v interface{}, k string) []interface{} {\n\treturn findAllImpl(v, k, make([]interface{}, 0, 10))\n}\n\nfunc findAllImpl(v interface{}, k string, r []interface{}) []interface{} {\n\tswitch v := v.(type) {\n\tcase map[string]interface{}:\n\t\tfor n, w := range v {\n\t\t\tif n == k {\n\t\t\t\tr = append(r, w)\n\t\t\t}\n\t\t\tr = findAllImpl(w, k, r)\n\t\t}\n\tcase []interface{}:\n\t\tfor _, w := range v {\n\t\t\tr = findAllImpl(w, k, r)\n\t\t}\n\t}\n\treturn r\n}\n"
  },
  {
    "path": "set_test.go",
    "content": "package dproxy\n\nimport \"testing\"\n\nfunc TestSet(t *testing.T) {\n\tv := parseJSON(`{\n\t\t\"items\" : [\n\t\t\t{\n\t\t\t\t\"name\": \"Bob\",\n\t\t\t\t\"age\": 20\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"name\": \"Mike\",\n\t\t\t\t\"age\": 23\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"name\": \"John\",\n\t\t\t\t\"age\": 22\n\t\t\t}\n\t\t]\n\t}`)\n\n\tnames, err := New(v).Q(\"name\").StringArray()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t} else if !equalStrings(names, []string{\"Bob\", \"Mike\", \"John\"}) {\n\t\tt.Error(\"unexpected names:\", names)\n\t}\n\n\tages, err := New(v).Q(\"age\").Int64Array()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t} else if !equalInts(ages, []int64{20, 23, 22}) {\n\t\tt.Error(\"unexpected ages:\", ages)\n\t}\n\t_ = ages\n}\n\nfunc TestSetTypeError(t *testing.T) {\n\tv := parseJSON(`[true, false, 0, true, false]`)\n\t_, err := New(v).ProxySet().BoolArray()\n\tif err == nil {\n\t\tt.Fatal(\"should fail\")\n\t}\n\terr2, ok := err.(Error)\n\tif !ok {\n\t\tt.Fatal(\"err is not Error:\", err)\n\t}\n\tif et := err2.ErrorType(); et != Etype {\n\t\tt.Fatal(\"unexpected ErrorType:\", et)\n\t}\n\tif ea := err2.FullAddress(); ea != \"[2]\" {\n\t\tt.Fatal(\"unexpected FullAddress:\", ea)\n\t}\n}\n"
  },
  {
    "path": "staticcheck.conf",
    "content": "# vim:set ft=toml:\n\nchecks = [\"all\"]\n\n# based on: github.com/koron-go/_skeleton/staticcheck.conf\n# $Hash:cd6871e83e780f6a2ce05386c0551034badf78b2ad40a76a8f6f5510$\n"
  },
  {
    "path": "type.go",
    "content": "package dproxy\n\n// Type is type of value.\ntype Type int\n\nconst (\n\t// Tunknown shows value is not supported.\n\tTunknown Type = iota\n\n\t// Tnil shows value is nil.\n\tTnil\n\n\t// Tbool shows value is bool.\n\tTbool\n\n\t// Tint64 shows value is int64.\n\tTint64\n\n\t// Tfloat64 shows value is float64.\n\tTfloat64\n\n\t// Tstring shows value is string.\n\tTstring\n\n\t// Tarray shows value is an array ([]interface{})\n\tTarray\n\n\t// Tmap shows value is a map (map[string]interface{})\n\tTmap\n)\n\n// detectType returns type of a value.\nfunc detectType(v interface{}) Type {\n\tif v == nil {\n\t\treturn Tnil\n\t}\n\tswitch v.(type) {\n\tcase bool:\n\t\treturn Tbool\n\tcase int, int32, int64:\n\t\treturn Tint64\n\tcase float32, float64:\n\t\treturn Tfloat64\n\tcase string:\n\t\treturn Tstring\n\tcase []interface{}:\n\t\treturn Tarray\n\tcase map[string]interface{}:\n\t\treturn Tmap\n\tdefault:\n\t\treturn Tunknown\n\t}\n}\n\nfunc (t Type) String() string {\n\tswitch t {\n\tcase Tunknown:\n\t\treturn \"unknown\"\n\tcase Tnil:\n\t\treturn \"nil\"\n\tcase Tbool:\n\t\treturn \"bool\"\n\tcase Tint64:\n\t\treturn \"int64\"\n\tcase Tfloat64:\n\t\treturn \"float64\"\n\tcase Tstring:\n\t\treturn \"string\"\n\tcase Tarray:\n\t\treturn \"array\"\n\tcase Tmap:\n\t\treturn \"map\"\n\tdefault:\n\t\treturn \"unknown\"\n\t}\n}\n"
  },
  {
    "path": "value.go",
    "content": "package dproxy\n\nimport (\n\t\"reflect\"\n\t\"strconv\"\n)\n\ntype valueProxy struct {\n\tvalue  interface{}\n\tparent frame\n\tlabel  string\n}\n\n// valueProxy implements Proxy.\nvar _ Proxy = (*valueProxy)(nil)\n\nfunc (p *valueProxy) Nil() bool {\n\treturn p.value == nil\n}\n\nfunc (p *valueProxy) Value() (interface{}, error) {\n\treturn p.value, nil\n}\n\nfunc (p *valueProxy) Bool() (bool, error) {\n\tswitch v := p.value.(type) {\n\tcase bool:\n\t\treturn v, nil\n\tdefault:\n\t\treturn false, typeError(p, Tbool, v)\n\t}\n}\n\ntype int64er interface {\n\tInt64() (int64, error)\n}\n\nfunc (p *valueProxy) Int64() (int64, error) {\n\tswitch v := p.value.(type) {\n\tcase int:\n\t\treturn int64(v), nil\n\tcase int32:\n\t\treturn int64(v), nil\n\tcase int64:\n\t\treturn v, nil\n\tcase float32:\n\t\treturn int64(v), nil\n\tcase float64:\n\t\treturn int64(v), nil\n\tcase int64er:\n\t\tw, err := v.Int64()\n\t\tif err != nil {\n\t\t\treturn 0, &errorProxy{\n\t\t\t\terrorType: EconvertFailure,\n\t\t\t\tparent:    p,\n\t\t\t\tinfoStr:   err.Error(),\n\t\t\t}\n\t\t}\n\t\treturn w, nil\n\tdefault:\n\t\treturn 0, typeError(p, Tint64, v)\n\t}\n}\n\ntype float64er interface {\n\tFloat64() (float64, error)\n}\n\nfunc (p *valueProxy) Float64() (float64, error) {\n\tswitch v := p.value.(type) {\n\tcase int:\n\t\treturn float64(v), nil\n\tcase int32:\n\t\treturn float64(v), nil\n\tcase int64:\n\t\treturn float64(v), nil\n\tcase float32:\n\t\treturn float64(v), nil\n\tcase float64:\n\t\treturn v, nil\n\tcase float64er:\n\t\tw, err := v.Float64()\n\t\tif err != nil {\n\t\t\treturn 0, &errorProxy{\n\t\t\t\terrorType: EconvertFailure,\n\t\t\t\tparent:    p,\n\t\t\t\tinfoStr:   err.Error(),\n\t\t\t}\n\t\t}\n\t\treturn w, nil\n\tdefault:\n\t\treturn 0, typeError(p, Tfloat64, v)\n\t}\n}\n\nfunc (p *valueProxy) String() (string, error) {\n\tswitch v := p.value.(type) {\n\tcase string:\n\t\treturn v, nil\n\tdefault:\n\t\treturn \"\", typeError(p, Tstring, v)\n\t}\n}\n\nfunc (p *valueProxy) Array() ([]interface{}, error) {\n\tswitch v := p.value.(type) {\n\tcase []interface{}:\n\t\treturn v, nil\n\tdefault:\n\t\treturn nil, typeError(p, Tarray, v)\n\t}\n}\n\nfunc (p *valueProxy) Map() (map[string]interface{}, error) {\n\tswitch v := p.value.(type) {\n\tcase map[string]interface{}:\n\t\treturn v, nil\n\tdefault:\n\t\treturn nil, typeError(p, Tmap, v)\n\t}\n}\n\nfunc (p *valueProxy) A(n int) Proxy {\n\tswitch v := p.value.(type) {\n\tcase []interface{}:\n\t\ta := \"[\" + strconv.Itoa(n) + \"]\"\n\t\tif n < 0 || n >= len(v) {\n\t\t\treturn notfoundError(p, a)\n\t\t}\n\t\treturn &valueProxy{\n\t\t\tvalue:  v[n],\n\t\t\tparent: p,\n\t\t\tlabel:  a,\n\t\t}\n\tdefault:\n\t\treturn requiredTypeError(p, Tarray, v)\n\t}\n}\n\nvar mapType = reflect.TypeOf(map[string]interface{}(nil))\n\nfunc (p *valueProxy) m(v map[string]interface{}, k string) Proxy {\n\ta := \".\" + k\n\tw, ok := v[k]\n\tif !ok {\n\t\treturn notfoundError(p, a)\n\t}\n\treturn &valueProxy{\n\t\tvalue:  w,\n\t\tparent: p,\n\t\tlabel:  a,\n\t}\n}\n\nfunc (p *valueProxy) M(k string) Proxy {\n\tif v, ok := p.value.(map[string]interface{}); ok {\n\t\treturn p.m(v, k)\n\t}\n\n\tif rv := reflect.ValueOf(p.value); rv.IsValid() && rv.Type().ConvertibleTo(mapType) {\n\t\tv, _ := rv.Convert(mapType).Interface().(map[string]interface{})\n\t\treturn p.m(v, k)\n\t}\n\n\treturn requiredTypeError(p, Tmap, p.value)\n}\n\nfunc (p *valueProxy) P(q string) Proxy {\n\treturn pointer(p, q)\n}\n\nfunc (p *valueProxy) ProxySet() ProxySet {\n\tswitch v := p.value.(type) {\n\tcase []interface{}:\n\t\treturn &setProxy{\n\t\t\tvalues: v,\n\t\t\tparent: p,\n\t\t}\n\tdefault:\n\t\treturn typeError(p, Tarray, v)\n\t}\n}\n\nfunc (p *valueProxy) Q(k string) ProxySet {\n\tw := findAll(p.value, k)\n\treturn &setProxy{\n\t\tvalues: w,\n\t\tparent: p,\n\t\tlabel:  \"..\" + k,\n\t}\n}\n\nfunc (p *valueProxy) findJPT(t string) Proxy {\n\tswitch v := p.value.(type) {\n\tcase map[string]interface{}:\n\t\treturn p.M(t)\n\tcase []interface{}:\n\t\tn, err := strconv.ParseUint(t, 10, 0)\n\t\tif err != nil {\n\t\t\treturn &errorProxy{\n\t\t\t\terrorType: EinvalidIndex,\n\t\t\t\tparent:    p,\n\t\t\t\tinfoStr:   err.Error(),\n\t\t\t}\n\t\t}\n\t\treturn p.A(int(n))\n\tdefault:\n\t\treturn &errorProxy{\n\t\t\terrorType: EmapNorArray,\n\t\t\tparent:    p,\n\t\t\tactual:    detectType(v),\n\t\t}\n\t}\n}\n\nfunc (p *valueProxy) parentFrame() frame {\n\treturn p.parent\n}\n\nfunc (p *valueProxy) frameLabel() string {\n\treturn p.label\n}\n"
  },
  {
    "path": "value_test.go",
    "content": "package dproxy\n\nimport \"testing\"\n\nfunc TestTypeError(t *testing.T) {\n\tt.Run(\"map at root\", func(t *testing.T) {\n\t\tv := &valueProxy{}\n\t\t_, err := v.M(\"foo\").Int64()\n\t\tassertError(t, err, \"not required types: required=map actual=nil: (root)\")\n\t})\n\tt.Run(\"map at child\", func(t *testing.T) {\n\t\tv := &valueProxy{\n\t\t\tparent: &valueProxy{},\n\t\t\tlabel:  \"foo\",\n\t\t}\n\t\t_, err := v.M(\"bar\").Int64()\n\t\tassertError(t, err, \"not required types: required=map actual=nil: foo\")\n\t})\n\n\tt.Run(\"array at root\", func(t *testing.T) {\n\t\tv := &valueProxy{}\n\t\t_, err := v.A(0).Int64()\n\t\tassertError(t, err, \"not required types: required=array actual=nil: (root)\")\n\t})\n\tt.Run(\"array at child\", func(t *testing.T) {\n\t\tv := &valueProxy{\n\t\t\tparent: &valueProxy{},\n\t\t\tlabel:  \"foo\",\n\t\t}\n\t\t_, err := v.A(0).Int64()\n\t\tassertError(t, err, \"not required types: required=array actual=nil: foo\")\n\t})\n}\n"
  }
]