Full Code of koron/go-dproxy for AI

main 81dfa780e5ac cached
24 files
40.1 KB
13.0k tokens
141 symbols
1 requests
Download .txt
Repository: koron/go-dproxy
Branch: main
Commit: 81dfa780e5ac
Files: 24
Total size: 40.1 KB

Directory structure:
gitextract_caioeg4v/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       └── go.yml
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── doc.go
├── drain.go
├── drain_test.go
├── error.go
├── frame.go
├── go.mod
├── go.sum
├── package_test.go
├── pointer.go
├── pointer_test.go
├── proxy.go
├── proxy_test.go
├── set.go
├── set_test.go
├── staticcheck.conf
├── type.go
├── value.go
└── value_test.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
  - package-ecosystem: "github-actions" # See documentation for possible values
    directory: "/" # Location of package manifests
    schedule:
      interval: "weekly"

# $Hash:c5d3212bc9191230f44684f4d30f030b6c70d515e68cbc9c3467c4d9$


================================================
FILE: .github/workflows/go.yml
================================================
name: Go

on: [push]

permissions:
  contents: write

env:
  GO_VERSION: 'oldstable'

jobs:

  check:
    name: Check main packages
    outputs:
      targets: ${{ steps.list.outputs.targets }}

    runs-on: ubuntu-latest

    steps:

    - uses: actions/checkout@v6
    - uses: actions/setup-go@v6
      with:
        go-version: ${{ env.GO_VERSION }}

    - name: List "main" packages to be released
      id: list
      shell: bash
      run: |
        found=0
        echo "targets<<__END__" >> "$GITHUB_OUTPUT"
        main_packages=$(go list -f '{{if (eq .Name "main")}}{{.ImportPath}} .{{slice .ImportPath (len .Module.Path)}}{{end}}' ./...)
        while read -r path dir; do
          [ -z "$path" ] && continue
          name=$(basename "$path")
          if [ -f "$dir/.norelease" ] ; then
            printf "Skipped %s\t(%s), due to %s/.norelease found\n" "$name" "$dir" "$dir"
          else
            found=1
            echo "$name $dir $path" >> "$GITHUB_OUTPUT"
            printf "Added   %s\t(%s) to the release\n" "$name" "$dir"
          fi
        done <<EOF
        $main_packages
        EOF
        echo "__END__" >> "$GITHUB_OUTPUT"
        if [ $found -eq 0 ] ; then
          echo "⛔ No packages found to release"
        fi

  build:
    name: Build

    needs: check

    env:
      RELEASE_TARGETS: ${{needs.check.outputs.targets}}

    strategy:
      fail-fast: false
      matrix:
        include:
        - { os: darwin,  arch: amd64, runner: macos-latest,     }
        - { os: darwin,  arch: arm64, runner: macos-latest,     }
        - { os: freebsd, arch: amd64, runner: ubuntu-latest,    }
        - { os: linux,   arch: arm64, runner: ubuntu-24.04-arm, }
        - { os: linux,   arch: amd64, runner: ubuntu-latest,    }
        - { os: windows, arch: amd64, runner: windows-latest,   }

    defaults:
      run:
        shell: ${{ matrix.os == 'freebsd' && 'freebsd {0}' || 'bash' }}

    runs-on: ${{ matrix.runner }}

    steps:

    - uses: actions/checkout@v6

    - uses: actions/setup-go@v6
      with:
        go-version: ${{ env.GO_VERSION }}

    - name: Setup env
      id: setup
      shell: bash
      run: |
        NAME="${GITHUB_REPOSITORY#${GITHUB_REPOSITORY_OWNER}/}"

        GOOS=${{ matrix.os }}
        GOARCH=${{ matrix.arch }}

        if [[ ${GITHUB_REF} =~ ^refs/tags/v[0-9]+\.[0-9]+ ]] ; then
          VERSION=${GITHUB_REF_NAME}
        else
          VERSION=SNAPSHOT
        fi

        case ${{ matrix.os }} in
          linux|freebsd)  PKGEXT=.tar.gz ;;
          darwin|windows) PKGEXT=.zip ;;
        esac

        case ${{ matrix.os }} in
          windows) choco install zip ;;
        esac

        echo "VERSION=${VERSION}" >> $GITHUB_ENV
        echo "GOOS=${GOOS}" >> $GITHUB_ENV
        echo "GOARCH=${GOARCH}" >> $GITHUB_ENV
        echo "CGO_ENABLED=1" >> $GITHUB_ENV
        echo "PKGNAME=${NAME}_${VERSION}_${GOOS}_${GOARCH}" >> $GITHUB_ENV
        echo "PKGEXT=${PKGEXT}" >> $GITHUB_ENV

    - name: Start FreeBSD VM
      if: matrix.os == 'freebsd'
      uses: vmactions/freebsd-vm@d1e65811565151536c0c894fff74f06351ed26e6 # v1.4.5
      with:
        usesh: true
        copyback: false
        disable-cache: true
        arch: ${{ matrix.arch }}

        envs: 'RELEASE_TARGETS PKGNAME PKGEXT'

        prepare: |
          echo "::group::Install Go"
          pkg install -y go

    - name: Test all
      run: |
        go test ./...

    - name: Build all "main" packages
      if: needs.check.outputs.targets != ''
      run: |
        while read -r name dir path ; do
          printf "building %s\t(%s)\n" "$name" "$dir"
          ( cd "$dir" && go build )
        done <<EOF
        $RELEASE_TARGETS
        EOF

    - name: Copyback from FreeBSD VM
      if: matrix.os == 'freebsd' && needs.check.outputs.targets != ''
      shell: bash
      run: |
        rsync -av --exclude .git -e ssh "freebsd:$HOME/work/" "$HOME/work/"

    - name: Archive
      if: needs.check.outputs.targets != ''
      shell: bash
      run: |
        mkdir -p _build/${PKGNAME}

        while read -r name dir path ; do
          cp "$dir/$name" _build/${PKGNAME}
        done <<EOF
        $RELEASE_TARGETS
        EOF

        cp -p LICENSE _build/${PKGNAME}
        cp -p README.md _build/${PKGNAME}

        case "${PKGEXT}" in
          ".tar.gz")
            tar caf _build/${PKGNAME}${PKGEXT} -C _build ${PKGNAME}
            ;;
          ".zip")
            (cd _build && zip -r9q ${PKGNAME}${PKGEXT} ${PKGNAME})
            ;;
        esac
        ls -laFR _build

    - name: Artifact upload
      if: needs.check.outputs.targets != ''
      uses: actions/upload-artifact@v7
      with:
        name: release-${{ env.GOOS }}_${{ env.GOARCH }}
        path: _build/${{ env.PKGNAME }}${{ env.PKGEXT }}

  create-release:
    name: Create release
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/')
    needs:
    - build
    steps:
    - uses: actions/download-artifact@v8
      with:
        pattern: release-*
        merge-multiple: true
    - run: ls -lafR
    - name: Release
      uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
      with:
        draft: true
        prerelease: ${{ contains(github.ref_name, '-alpha.') || contains(github.ref_name, '-beta.') }}
        files: |
          *.tar.gz
          *.zip
        fail_on_unmatched_files: ${{ needs.check.outputs.targets != '' }}
        generate_release_notes: true
        append_body: true

# based on: github.com/koron-go/_skeleton/.github/workflows/go.yml
# $Hash:01f9cf8649094e7b57bcfa7103802dcd6953b81d214480fccdfdfbc4$


================================================
FILE: .gitignore
================================================
/tags
/tmp/


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2015 MURAOKA Taro <koron.kaoriya@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: Makefile
================================================
# Get relative paths of all "main" packages
MAIN_PACKAGE ?= $(shell go list -f '{{if (eq .Name "main")}}.{{slice .ImportPath (len .Module.Path)}}{{end}}' ./...)

TEST_PACKAGE ?= ./...

.PHONY: build
build:
	go build -gcflags '-e' ./...

.PHONY: test
test:
	go test $(TEST_PACKAGE)

.PHONY: race
race:
	go test -race $(TEST_PACKAGE)

.PHONY: bench
bench:
	go test -bench $(TEST_PACKAGE)

.PHONY: tags
tags:
	gotags -f tags -R .

.PHONY: cover
cover:
	mkdir -p tmp
	go test -coverprofile tmp/_cover.out $(TEST_PACKAGE)
	go tool cover -html tmp/_cover.out -o tmp/cover.html

.PHONY: checkall
checkall: vet staticcheck

.PHONY: vet
vet:
	go vet $(TEST_PACKAGE)

.PHONY: staticcheck
staticcheck:
	staticcheck $(TEST_PACKAGE)

.PHONY: clean
clean:
	go clean
	rm -f tags
	rm -f tmp/_cover.out tmp/cover.html

.PHONY: upgradable
upgradable:
	@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

.PHONY: upgradable-all
upgradable-all:
	@go list -m -u -f '{{if .Update}}{{.Path}} {{.Version}} [{{.Update.Version}}]{{end}}' all

# Build all "main" packages
.PHONY: main-build
main-build:
	@for d in $(MAIN_PACKAGE) ; do \
	  echo "cd $$d && go build -gcflags '-e'" ; \
	  ( cd $$d && go build -gcflags '-e' ) ; \
	done

# Clean all "main" packages
.PHONY: main-clean
main-clean:
	@for d in $(MAIN_PACKAGE) ; do \
	  echo "cd $$d && go clean" ; \
	  ( cd $$d && go clean ) ; \
	done

# based on: github.com/koron-go/_skeleton/Makefile
# $Hash:93a5966a0297543bcdd82a4dd9c2d60232a1b02c49cfa0b4341fdb71$


================================================
FILE: README.md
================================================
# dProxy - document proxy

[![GoDoc](https://godoc.org/github.com/koron/go-dproxy?status.svg)](https://godoc.org/github.com/koron/go-dproxy)
[![Actions/Go](https://github.com/koron/go-dproxy/workflows/Go/badge.svg)](https://github.com/koron/go-dproxy/actions?query=workflow%3AGo)
[![Go Report Card](https://goreportcard.com/badge/github.com/koron/go-dproxy)](https://goreportcard.com/report/github.com/koron/go-dproxy)

dProxy is a proxy to access `interface{}` (document) by simple query.
It is intented to be used with `json.Unmarshal()` or `json.NewDecorder()`.

See codes for overview.

```go
import (
  "encoding/json"

  "github.com/koron/go-dproxy"
)

var v interface{}
json.Unmarshal([]byte(`{
  "cities": [ "tokyo", 100, "osaka", 200, "hakata", 300 ],
  "data": {
    "custom": [ "male", 23, "female", 24 ]
  }
}`), &v)

// s == "tokyo", got a string.
s, _ := dproxy.New(v).M("cities").A(0).String()

// err != nil, type not matched.
_, err := dproxy.New(v).M("cities").A(0).Float64()

// n == 200, got a float64
n, _ := dproxy.New(v).M("cities").A(3).Float64()

// can be chained.
dproxy.New(v).M("data").M("custom").A(0).String()

// err.Error() == "not found: data.kustom", wrong query can be verified.
_, err = dproxy.New(v).M("data").M("kustom").String()
```


## Getting started

### Proxy

1.  Wrap a value (`interface{}`) with `dproxy.New()` get `dproxy.Proxy`.

    ```go
    p := dproxy.New(v) // v should be a value of interface{}
    ```

2.  Query as a map (`map[string]interface{}`)by `M()`, returns `dproxy.Proxy`.

    ```go
    p.M("cities")
    ```

3.  Query as an array (`[]interface{}`) with `A()`, returns `dproxy.Proxy`.

    ```go
    p.A(3)
    ```

4.  Therefore, can be chained queries.

    ```go
    p.M("cities").A(3)
    ```

5.  Get a value finally.

    ```go
    n, _ := p.M("cities").A(3).Int64()
    ```

6.  You'll get an error when getting a value, if there were some mistakes.

    ```go
    // OOPS! "kustom" is typo, must be "custom"
    _, err := p.M("data").M("kustom").A(3).Int64()

    // "not found: data.kustom"
    fmt.Println(err)
    ```

7.  If you tried to get a value as different type, get an error.

    ```go
    // OOPS! "cities[3]" (=200) should be float64 or int64.
    _, err := p.M("cities").A(3).String()

    // "not matched types: expected=string actual=float64: cities[3]"
    fmt.Println(err)
    ```

8.  You can verify queries easily.

### Drain

Getting value and error from Proxy/ProxySet multiple times, is very awful.
It must check error when every getting values.

```go
p := dproxy.New(v)
v1, err := p.M("cities").A(3).Int64()
if err != nil {
    return err
}
v2, err := p.M("data").M("kustom").A(3).Int64()
if err != nil {
    return err
}
v3, err := p.M("cities").A(3).String()
if err != nil {
    return err
}
```

It can be rewrite as simple like below with `dproxy.Drain`

```go
var d Drain
p := dproxy.New(v)
v1 := d.Int64(p.M("cities").A(3))
v2 := d.Int64(p.M("data").M("kustom").A(3))
v3 := d.String(p.M("cities").A(3))
if err := d.CombineErrors(); err != nil {
    return err
}
```

### JSON Pointer

JSON Pointer can be used to query `interface{}`

```go
v1, err := dproxy.New(v).P("/cities/0").Int64()
```

or

```go
v1, err := dproxy.Pointer(v, "/cities/0").Int64()
```

See [RFC6901][1] for details of JSON Pointer.


## LICENSE

MIT license.  See LICENSE.

[1]: https://tools.ietf.org/html/rfc6901


================================================
FILE: doc.go
================================================
/*
Package dproxy provides a proxy to adccess `interface{}` (document) by simple
query.  It is intended to be used with `"encoding/json".Unmarshal()` or so.
*/
package dproxy


================================================
FILE: drain.go
================================================
package dproxy

import "bytes"

// Drain stores errors from Proxy or ProxySet.
type Drain struct {
	errors []error
}

// Has returns true if the drain stored some of errors.
func (d *Drain) Has() bool {
	return d != nil && len(d.errors) > 0
}

// First returns a stored error.  Returns nil if there are no errors.
func (d *Drain) First() error {
	if d == nil || len(d.errors) == 0 {
		return nil
	}
	return d.errors[0]
}

// All returns all errors which stored.  Return nil if no errors stored.
func (d *Drain) All() []error {
	if d == nil || len(d.errors) == 0 {
		return nil
	}
	a := make([]error, 0, len(d.errors))
	return append(a, d.errors...)
}

// CombineErrors returns an error which combined all stored errors.  Return nil
// if not erros stored.
func (d *Drain) CombineErrors() error {
	if d == nil || len(d.errors) == 0 {
		return nil
	}
	return drainError(d.errors)
}

func (d *Drain) put(err error) {
	if err == nil {
		return
	}
	d.errors = append(d.errors, err)
}

// Bool returns bool value and stores an error.
func (d *Drain) Bool(p Proxy) bool {
	v, err := p.Bool()
	d.put(err)
	return v
}

// Int64 returns int64 value and stores an error.
func (d *Drain) Int64(p Proxy) int64 {
	v, err := p.Int64()
	d.put(err)
	return v
}

// Float64 returns float64 value and stores an error.
func (d *Drain) Float64(p Proxy) float64 {
	v, err := p.Float64()
	d.put(err)
	return v
}

// String returns string value and stores an error.
func (d *Drain) String(p Proxy) string {
	v, err := p.String()
	d.put(err)
	return v
}

// Array returns []interface{} value and stores an error.
func (d *Drain) Array(p Proxy) []interface{} {
	v, err := p.Array()
	d.put(err)
	return v
}

// Map returns map[string]interface{} value and stores an error.
func (d *Drain) Map(p Proxy) map[string]interface{} {
	v, err := p.Map()
	d.put(err)
	return v
}

// BoolArray returns []bool value and stores an error.
func (d *Drain) BoolArray(ps ProxySet) []bool {
	v, err := ps.BoolArray()
	d.put(err)
	return v
}

// Int64Array returns []int64 value and stores an error.
func (d *Drain) Int64Array(ps ProxySet) []int64 {
	v, err := ps.Int64Array()
	d.put(err)
	return v
}

// Float64Array returns []float64 value and stores an error.
func (d *Drain) Float64Array(ps ProxySet) []float64 {
	v, err := ps.Float64Array()
	d.put(err)
	return v
}

// StringArray returns []string value and stores an error.
func (d *Drain) StringArray(ps ProxySet) []string {
	v, err := ps.StringArray()
	d.put(err)
	return v
}

// ArrayArray returns [][]interface{} value and stores an error.
func (d *Drain) ArrayArray(ps ProxySet) [][]interface{} {
	v, err := ps.ArrayArray()
	d.put(err)
	return v
}

// MapArray returns []map[string]interface{} value and stores an error.
func (d *Drain) MapArray(ps ProxySet) []map[string]interface{} {
	v, err := ps.MapArray()
	d.put(err)
	return v
}

// ProxyArray returns []Proxy value and stores an error.
func (d *Drain) ProxyArray(ps ProxySet) []Proxy {
	v, err := ps.ProxyArray()
	d.put(err)
	return v
}

type drainError []error

func (derr drainError) Error() string {
	b := bytes.Buffer{}
	for i, err := range derr {
		if i > 0 {
			_, _ = b.WriteString("; ")
		}
		_, _ = b.WriteString(err.Error())
	}
	return b.String()
}


================================================
FILE: drain_test.go
================================================
package dproxy

import (
	"testing"
)

func TestDrainBool(t *testing.T) {
	v := parseJSON(`{
		"foo": true,
		"bar": false
	}`)

	d := new(Drain)

	foo := d.Bool(New(v).M("foo"))
	if d.Has() {
		t.Error(d.First())
	} else if foo != true {
		t.Errorf("foo must be true")
	}

	bar := d.Bool(New(v).M("bar"))
	if d.Has() {
		t.Error(d.First())
	} else if bar != false {
		t.Errorf("bar must be false")
	}

	baz := d.Bool(New(v).M("baz"))
	if !d.Has() {
		t.Error("baz must not exist")
	} else if err := d.First(); err == nil || err.Error() != "not found: baz" {
		t.Errorf("unexpected error: %s", err)
	}
	_ = baz
}


================================================
FILE: error.go
================================================
package dproxy

import (
	"fmt"
	"strconv"
)

// ErrorType is type of errors
type ErrorType int

const (
	// Etype means expected type is not matched with actual.
	Etype ErrorType = iota + 1

	// Enotfound means key or index doesn't exist.
	Enotfound

	// EmapNorArray means target is not a map nor an array (for JSON Pointer)
	EmapNorArray

	// EconvertFailure means value conversion is failed.
	EconvertFailure

	// EinvalidIndex means token is invalid as index (for JSON Pointer)
	EinvalidIndex

	// EinvalidQuery means query is invalid as JSON Pointer.
	EinvalidQuery

	// ErequiredType means the type mismatch against user required one.
	// For example M() requires map, A() requires array.
	ErequiredType
)

func (et ErrorType) String() string {
	switch et {
	case Etype:
		return "Etype"
	case Enotfound:
		return "Enotfound"
	case EmapNorArray:
		return "EmapNorArray"
	case EconvertFailure:
		return "EconvertFailure"
	case EinvalidIndex:
		return "EinvalidIndex"
	case EinvalidQuery:
		return "EinvalidQuery"
	case ErequiredType:
		return "ErequiredType"
	default:
		return "Eunknown"
	}
}

// Error get detail information of the errror.
type Error interface {
	// ErrorType returns type of error.
	ErrorType() ErrorType

	// FullAddress returns query string where cause first error.
	FullAddress() string
}

type errorProxy struct {
	errorType ErrorType
	parent    frame
	label     string

	expected Type
	actual   Type
	infoStr  string
}

// errorProxy implements error, Proxy and ProxySet.
var (
	_ error    = (*errorProxy)(nil)
	_ Proxy    = (*errorProxy)(nil)
	_ ProxySet = (*errorProxy)(nil)
)

func (p *errorProxy) Nil() bool {
	return false
}

func (p *errorProxy) Value() (interface{}, error) {
	return nil, p
}

func (p *errorProxy) Bool() (bool, error) {
	return false, p
}

func (p *errorProxy) Int64() (int64, error) {
	return 0, p
}

func (p *errorProxy) Float64() (float64, error) {
	return 0, p
}

func (p *errorProxy) String() (string, error) {
	return "", p
}

func (p *errorProxy) Array() ([]interface{}, error) {
	return nil, p
}

func (p *errorProxy) Map() (map[string]interface{}, error) {
	return nil, p
}

func (p *errorProxy) A(n int) Proxy {
	return p
}

func (p *errorProxy) M(k string) Proxy {
	return p
}

func (p *errorProxy) P(q string) Proxy {
	return p
}

func (p *errorProxy) Empty() bool {
	return true
}

func (p *errorProxy) Len() int {
	return 0
}

func (p *errorProxy) BoolArray() ([]bool, error) {
	return nil, p
}

func (p *errorProxy) Int64Array() ([]int64, error) {
	return nil, p
}

func (p *errorProxy) Float64Array() ([]float64, error) {
	return nil, p
}

func (p *errorProxy) StringArray() ([]string, error) {
	return nil, p
}

func (p *errorProxy) ArrayArray() ([][]interface{}, error) {
	return nil, p
}

func (p *errorProxy) MapArray() ([]map[string]interface{}, error) {
	return nil, p
}

func (p *errorProxy) ProxyArray() ([]Proxy, error) {
	return nil, p
}

func (p *errorProxy) ProxySet() ProxySet {
	return p
}

func (p *errorProxy) Q(k string) ProxySet {
	return p
}

func (p *errorProxy) Qc(k string) ProxySet {
	return p
}

func (p *errorProxy) findJPT(t string) Proxy {
	return p
}

func (p *errorProxy) parentFrame() frame {
	return p.parent
}

func (p *errorProxy) frameLabel() string {
	return p.label
}

func (p *errorProxy) Error() string {
	switch p.errorType {
	case Etype:
		return fmt.Sprintf("not matched types: expected=%s actual=%s: %s",
			p.expected.String(), p.actual.String(), p.FullAddress())
	case Enotfound:
		return fmt.Sprintf("not found: %s", p.FullAddress())
	case EmapNorArray:
		// FIXME: better error message.
		return fmt.Sprintf("not map nor array: actual=%s: %s",
			p.actual.String(), p.FullAddress())
	case EconvertFailure:
		return fmt.Sprintf("convert error: %s: %s", p.infoStr, p.FullAddress())
	case EinvalidIndex:
		// FIXME: better error message.
		return fmt.Sprintf("invalid index: %s: %s", p.infoStr, p.FullAddress())
	case EinvalidQuery:
		// FIXME: better error message.
		return fmt.Sprintf("invalid query: %s: %s", p.infoStr, p.FullAddress())
	case ErequiredType:
		return fmt.Sprintf("not required types: required=%s actual=%s: %s",
			p.expected.String(), p.actual.String(), p.FullAddress())
	default:
		return fmt.Sprintf("unexpected: %s", p.FullAddress())
	}
}

func (p *errorProxy) ErrorType() ErrorType {
	return p.errorType
}

func (p *errorProxy) FullAddress() string {
	return fullAddress(p)
}

func typeError(p frame, expected Type, actual interface{}) *errorProxy {
	return &errorProxy{
		errorType: Etype,
		parent:    p,
		expected:  expected,
		actual:    detectType(actual),
	}
}

func requiredTypeError(p frame, expected Type, actual interface{}) *errorProxy {
	return &errorProxy{
		errorType: ErequiredType,
		parent:    p,
		expected:  expected,
		actual:    detectType(actual),
	}
}

func elementTypeError(p frame, index int, expected Type, actual interface{}) *errorProxy {
	q := &simpleFrame{
		parent: p,
		label:  "[" + strconv.Itoa(index) + "]",
	}
	return typeError(q, expected, actual)
}

func notfoundError(p frame, address string) *errorProxy {
	return &errorProxy{
		errorType: Enotfound,
		parent:    p,
		label:     address,
	}
}


================================================
FILE: frame.go
================================================
package dproxy

type frame interface {
	// parentFrame returns parent frame.
	parentFrame() frame
	// frameLabel return label of frame.
	frameLabel() string
}

func fullAddress(f frame) string {
	x := 0
	for g := f; g != nil; g = g.parentFrame() {
		x += len(g.frameLabel())
	}
	if x == 0 {
		return "(root)"
	}
	b := make([]byte, x)
	for g := f; g != nil; g = g.parentFrame() {
		x -= len(g.frameLabel())
		copy(b[x:], g.frameLabel())
	}
	if b[0] == '.' {
		return string(b[1:])
	}
	return string(b)
}

type simpleFrame struct {
	parent frame
	label  string
}

var _ frame = (*simpleFrame)(nil)

func (f *simpleFrame) parentFrame() frame {
	return f.parent
}

func (f *simpleFrame) frameLabel() string {
	return f.label
}


================================================
FILE: go.mod
================================================
module github.com/koron/go-dproxy

go 1.13


================================================
FILE: go.sum
================================================


================================================
FILE: package_test.go
================================================
package dproxy

import (
	"fmt"
	"reflect"
	"testing"
)

func assertEquals(t *testing.T, actual, expected interface{}, format string, a ...interface{}) {
	t.Helper()
	if !reflect.DeepEqual(actual, expected) {
		msg := fmt.Sprintf(format, a...)
		t.Errorf("not equal: %s\nexpect=%+v\nactual=%+v", msg, expected, actual)
	}
}

func assertError(t *testing.T, err error, exp string) {
	t.Helper()
	if err == nil {
		t.Fatalf("should fail with: %s", exp)
	}
	if act := err.Error(); act != exp {
		t.Fatalf("unexpected error:\nexpect=%s\nactual=%s\n", exp, act)
	}
}


================================================
FILE: pointer.go
================================================
package dproxy

import "strings"

var jptR = strings.NewReplacer("~1", "/", "~0", "~")

func unescapeJPT(t string) string {
	return jptR.Replace(t)
}

func pointer(p Proxy, q string) Proxy {
	if len(q) == 0 {
		return p
	}
	if q[0] != '/' {
		return &errorProxy{
			errorType: EinvalidQuery,
			parent:    p,
			infoStr:   "not start with '/'",
		}
	}
	for _, t := range strings.Split(q[1:], "/") {
		p = p.findJPT(unescapeJPT(t))
	}
	return p
}

// Pointer returns a Proxy which pointed by JSON Pointer's query q
func Pointer(v interface{}, q string) Proxy {
	return pointer(New(v), q)
}


================================================
FILE: pointer_test.go
================================================
package dproxy

import "testing"

func TestUnescapeJPT(t *testing.T) {
	f := func(d, expect string) {
		s := unescapeJPT(d)
		if s != expect {
			t.Errorf("unescapeJPT(%q) should be %q but actually %q", d, expect, s)
		}
	}
	f("foo", "foo")
	f("bar", "bar")
	f("~0", "~")
	f("foo~0bar", "foo~bar")
	f("~1", "/")
	f("foo~1bar", "foo/bar")
	f("~01", "~1")
	f("foo~01bar", "foo~1bar")
	f("~10", "/0")
}

func TestPointerInvalidQuery(t *testing.T) {
	p := Pointer(nil, "invalid")
	err, ok := p.(*errorProxy)
	if !ok {
		t.Fatalf("it should be *errorProxy but: %+v", p)
	}
	if err.errorType != EinvalidQuery {
		t.Fatalf("errorType should be EinvalidQuery but: %s", err.errorType)
	}
}

func TestPointer(t *testing.T) {
	f := func(q string, d, expected interface{}) {
		p := Pointer(d, q)
		v, err := p.Value()
		if err != nil {
			t.Errorf("Pointer:%q for %+v failed: %s", q, d, err)
			return
		}
		assertEquals(t, v, expected, "Pointer:%q for %+v", q, d)
	}

	v := parseJSON(`{
		"cities": [ "tokyo", 100, "osaka", 200, "hakata", 300 ],
		"data": {
			"custom": [ "male", 21, "female", 22 ]
		}
	}`)
	f("", v, v)
	f("/cities", v, parseJSON(`["tokyo",100,"osaka",200,"hakata",300]`))
	f("/cities/0", v, "tokyo")
	f("/cities/1", v, float64(100))
	f("/cities/2", v, "osaka")
	f("/cities/3", v, float64(200))
	f("/cities/4", v, "hakata")
	f("/cities/5", v, float64(300))
	f("/data/custom", v, parseJSON(`["male",21,"female",22]`))

	// Example from RFC6901 https://tools.ietf.org/html/rfc6901
	w := parseJSON(`{
		"foo": ["bar", "baz"],
		"": 0,
		"a/b": 1,
		"c%d": 2,
		"e^f": 3,
		"g|h": 4,
		"i\\j": 5,
		"k\"l": 6,
		" ": 7,
		"m~n": 8
	}`)
	f("", w, w)
	f("/foo", w, parseJSON(`["bar","baz"]`))
	f("/foo/0", w, "bar")
	f("/", w, float64(0))
	f("/a~1b", w, float64(1))
	f("/c%d", w, float64(2))
	f("/e^f", w, float64(3))
	f("/g|h", w, float64(4))
	f("/i\\j", w, float64(5))
	f("/k\"l", w, float64(6))
	f("/ ", w, float64(7))
	f("/m~0n", w, float64(8))
}


================================================
FILE: proxy.go
================================================
package dproxy

// Proxy is a proxy to access a document (interface{}).
type Proxy interface {
	// Nil returns true, if target value is nil.
	Nil() bool

	// Value returns a proxied value.  If there are no values, it returns
	// error.
	Value() (interface{}, error)

	// Bool returns its value.  If value isn't the type, it returns error.
	Bool() (bool, error)

	// Int64 returns its value.  If value isn't the type, it returns error.
	Int64() (int64, error)

	// Float64 returns its value.  If value isn't the type, it returns error.
	Float64() (float64, error)

	// String returns its value.  If value isn't the type, it returns error.
	String() (string, error)

	// Array returns its value.  If value isn't the type, it returns error.
	Array() ([]interface{}, error)

	// Map returns its value.  If value isn't the type, it returns error.
	Map() (map[string]interface{}, error)

	// A returns an item from value treated as the array.
	A(n int) Proxy

	// M returns an item from value treated as the map.
	M(k string) Proxy

	// P returns which pointed by JSON Pointer's query q.
	P(q string) Proxy

	// ProxySet returns a set which converted from its array value.
	ProxySet() ProxySet

	// Q returns set of all items which property matchs with k.
	Q(k string) ProxySet

	// findJPT returns a match of JSON Pointer's Token t.
	findJPT(t string) Proxy

	// Proxy implements frame.
	frame
}

// ProxySet proxies to access to set.
type ProxySet interface {
	// Empty returns true when the set is empty.
	Empty() bool

	// Len returns count of items in the set.
	Len() int

	// BoolArray returns []bool which converterd from the set.
	BoolArray() ([]bool, error)

	// Int64Array returns []int64 which converterd from the set.
	Int64Array() ([]int64, error)

	// Float64Array returns []float64 which converterd from the set.
	Float64Array() ([]float64, error)

	// StringArray returns []string which converterd from the set.
	StringArray() ([]string, error)

	// ArrayArray returns [][]interface{} which converterd from the set.
	ArrayArray() ([][]interface{}, error)

	// MapArray returns []map[string]interface{} which converterd from the set.
	MapArray() ([]map[string]interface{}, error)

	// ProxyArray returns []Proxy which wrap each items.
	ProxyArray() ([]Proxy, error)

	// A returns an proxy for index in the set.
	A(n int) Proxy

	// Q returns set of all items which property matchs with k.
	Q(k string) ProxySet

	// Qc returns set of property of all items.
	Qc(k string) ProxySet

	// Proxy implements frame.
	frame
}

// New creates a new Proxy instance for v.
func New(v interface{}) Proxy {
	return &valueProxy{value: v}
}

// NewSet create a new ProxySet instance for v.
func NewSet(v []interface{}) ProxySet {
	return &setProxy{values: v}
}


================================================
FILE: proxy_test.go
================================================
package dproxy

import (
	"encoding/json"
	"testing"
)

func parseJSON(s string) interface{} {
	var v interface{}
	if err := json.Unmarshal([]byte(s), &v); err != nil {
		panic(err)
	}
	return v
}

func equalStrings(a, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	for i, s := range a {
		if s != b[i] {
			return false
		}
	}
	return true
}

func equalInts(a, b []int64) bool {
	if len(a) != len(b) {
		return false
	}
	for i, s := range a {
		if s != b[i] {
			return false
		}
	}
	return true
}

func TestReadme(t *testing.T) {
	v := parseJSON(`{
		"cities": [ "tokyo", 100, "osaka", 200, "hakata", 300 ],
		"data": {
			"custom": [ "male", 21, "female", 22 ]
		}
	}`)

	s, err := New(v).M("cities").A(0).String()
	if s != "tokyo" {
		t.Error("cities[0] must be \"tokyo\":", err)
	}

	_, err = New(v).M("cities").A(0).Float64()
	if err == nil {
		t.Error("cities[0] (float64) must be failed:", err)
	}

	n, err := New(v).M("cities").A(1).Float64()
	if n != 100 {
		t.Error("cities[1] must be 100:", err)
	}

	s2, err := New(v).M("data").M("custom").A(2).String()
	if s2 != "female" {
		t.Error("data.custom[2] must be \"female\":", err)
	}

	_, err = New(v).M("data").M("kustom").String()
	if err == nil || err.Error() != "not found: data.kustom" {
		t.Error("err is not \"not found: data.kustom\":", err)
	}
}

func TestMapBool(t *testing.T) {
	v := parseJSON(`{
		"foo": true,
		"bar": false
	}`)

	// check "foo"
	foo, err := New(v).M("foo").Bool()
	if err != nil {
		t.Error(err)
	} else if foo != true {
		t.Errorf("foo must be true")
	}

	// check "bar"
	bar, err := New(v).M("bar").Bool()
	if err != nil {
		t.Error(err)
	} else if bar != false {
		t.Errorf("bar must be false")
	}
}

type wrappedMap map[string]interface{}

func TestWrappedMap(t *testing.T) {
	v := wrappedMap{
		"foo": 123,
	}
	n, err := New(v).M("foo").Int64()
	if err != nil {
		t.Fatalf("failed: %s", err)
	}
	if n != 123 {
		t.Fatalf("unexpected value: %d", n)
	}
}


================================================
FILE: set.go
================================================
package dproxy

import "strconv"

type setProxy struct {
	values []interface{}
	parent frame
	label  string
}

// setProxy implements ProxySet
var _ ProxySet = (*setProxy)(nil)

func (p *setProxy) Empty() bool {
	return p.Len() == 0
}

func (p *setProxy) Len() int {
	return len(p.values)
}

func (p *setProxy) BoolArray() ([]bool, error) {
	r := make([]bool, len(p.values))
	for i, v := range p.values {
		switch v := v.(type) {
		case bool:
			r[i] = v
		default:
			return nil, elementTypeError(p, i, Tbool, v)
		}
	}
	return r, nil
}

func (p *setProxy) Int64Array() ([]int64, error) {
	r := make([]int64, len(p.values))
	for i, v := range p.values {
		switch v := v.(type) {
		case int:
			r[i] = int64(v)
		case int32:
			r[i] = int64(v)
		case int64:
			r[i] = v
		case float32:
			r[i] = int64(v)
		case float64:
			r[i] = int64(v)
		default:
			return nil, elementTypeError(p, i, Tint64, v)
		}
	}
	return r, nil
}

func (p *setProxy) Float64Array() ([]float64, error) {
	r := make([]float64, len(p.values))
	for i, v := range p.values {
		switch v := v.(type) {
		case int:
			r[i] = float64(v)
		case int32:
			r[i] = float64(v)
		case int64:
			r[i] = float64(v)
		case float32:
			r[i] = float64(v)
		case float64:
			r[i] = v
		default:
			return nil, elementTypeError(p, i, Tfloat64, v)
		}
	}
	return r, nil
}

func (p *setProxy) StringArray() ([]string, error) {
	r := make([]string, len(p.values))
	for i, v := range p.values {
		switch v := v.(type) {
		case string:
			r[i] = v
		default:
			return nil, elementTypeError(p, i, Tstring, v)
		}
	}
	return r, nil
}

func (p *setProxy) ArrayArray() ([][]interface{}, error) {
	r := make([][]interface{}, len(p.values))
	for i, v := range p.values {
		switch v := v.(type) {
		case []interface{}:
			r[i] = v
		default:
			return nil, elementTypeError(p, i, Tarray, v)
		}
	}
	return r, nil
}

func (p *setProxy) MapArray() ([]map[string]interface{}, error) {
	r := make([]map[string]interface{}, len(p.values))
	for i, v := range p.values {
		switch v := v.(type) {
		case map[string]interface{}:
			r[i] = v
		default:
			return nil, elementTypeError(p, i, Tmap, v)
		}
	}
	return r, nil
}

func (p *setProxy) ProxyArray() ([]Proxy, error) {
	r := make([]Proxy, 0, len(p.values))
	for i, v := range p.values {
		r = append(r, &valueProxy{
			value:  v,
			parent: p,
			label:  "[" + strconv.Itoa(i) + "]",
		})
	}
	return r, nil
}

func (p *setProxy) A(n int) Proxy {
	a := "[" + strconv.Itoa(n) + "]"
	if n < 0 || n >= len(p.values) {
		return notfoundError(p, a)
	}
	return &valueProxy{
		value:  p.values[n],
		parent: p,
		label:  a,
	}
}

func (p *setProxy) Q(k string) ProxySet {
	w := findAll(p.values, k)
	return &setProxy{
		values: w,
		parent: p,
		label:  ".." + k,
	}
}

func (p *setProxy) Qc(k string) ProxySet {
	r := make([]interface{}, 0, len(p.values))
	for _, v := range p.values {
		switch v := v.(type) {
		case map[string]interface{}:
			if w, ok := v[k]; ok {
				r = append(r, w)
			}
		}
	}
	return &setProxy{
		values: r,
		parent: p,
		label:  ".." + k,
	}
}

func (p *setProxy) parentFrame() frame {
	return p.parent
}

func (p *setProxy) frameLabel() string {
	return p.label
}

func findAll(v interface{}, k string) []interface{} {
	return findAllImpl(v, k, make([]interface{}, 0, 10))
}

func findAllImpl(v interface{}, k string, r []interface{}) []interface{} {
	switch v := v.(type) {
	case map[string]interface{}:
		for n, w := range v {
			if n == k {
				r = append(r, w)
			}
			r = findAllImpl(w, k, r)
		}
	case []interface{}:
		for _, w := range v {
			r = findAllImpl(w, k, r)
		}
	}
	return r
}


================================================
FILE: set_test.go
================================================
package dproxy

import "testing"

func TestSet(t *testing.T) {
	v := parseJSON(`{
		"items" : [
			{
				"name": "Bob",
				"age": 20
			},
			{
				"name": "Mike",
				"age": 23
			},
			{
				"name": "John",
				"age": 22
			}
		]
	}`)

	names, err := New(v).Q("name").StringArray()
	if err != nil {
		t.Fatal(err)
	} else if !equalStrings(names, []string{"Bob", "Mike", "John"}) {
		t.Error("unexpected names:", names)
	}

	ages, err := New(v).Q("age").Int64Array()
	if err != nil {
		t.Fatal(err)
	} else if !equalInts(ages, []int64{20, 23, 22}) {
		t.Error("unexpected ages:", ages)
	}
	_ = ages
}

func TestSetTypeError(t *testing.T) {
	v := parseJSON(`[true, false, 0, true, false]`)
	_, err := New(v).ProxySet().BoolArray()
	if err == nil {
		t.Fatal("should fail")
	}
	err2, ok := err.(Error)
	if !ok {
		t.Fatal("err is not Error:", err)
	}
	if et := err2.ErrorType(); et != Etype {
		t.Fatal("unexpected ErrorType:", et)
	}
	if ea := err2.FullAddress(); ea != "[2]" {
		t.Fatal("unexpected FullAddress:", ea)
	}
}


================================================
FILE: staticcheck.conf
================================================
# vim:set ft=toml:

checks = ["all"]

# based on: github.com/koron-go/_skeleton/staticcheck.conf
# $Hash:cd6871e83e780f6a2ce05386c0551034badf78b2ad40a76a8f6f5510$


================================================
FILE: type.go
================================================
package dproxy

// Type is type of value.
type Type int

const (
	// Tunknown shows value is not supported.
	Tunknown Type = iota

	// Tnil shows value is nil.
	Tnil

	// Tbool shows value is bool.
	Tbool

	// Tint64 shows value is int64.
	Tint64

	// Tfloat64 shows value is float64.
	Tfloat64

	// Tstring shows value is string.
	Tstring

	// Tarray shows value is an array ([]interface{})
	Tarray

	// Tmap shows value is a map (map[string]interface{})
	Tmap
)

// detectType returns type of a value.
func detectType(v interface{}) Type {
	if v == nil {
		return Tnil
	}
	switch v.(type) {
	case bool:
		return Tbool
	case int, int32, int64:
		return Tint64
	case float32, float64:
		return Tfloat64
	case string:
		return Tstring
	case []interface{}:
		return Tarray
	case map[string]interface{}:
		return Tmap
	default:
		return Tunknown
	}
}

func (t Type) String() string {
	switch t {
	case Tunknown:
		return "unknown"
	case Tnil:
		return "nil"
	case Tbool:
		return "bool"
	case Tint64:
		return "int64"
	case Tfloat64:
		return "float64"
	case Tstring:
		return "string"
	case Tarray:
		return "array"
	case Tmap:
		return "map"
	default:
		return "unknown"
	}
}


================================================
FILE: value.go
================================================
package dproxy

import (
	"reflect"
	"strconv"
)

type valueProxy struct {
	value  interface{}
	parent frame
	label  string
}

// valueProxy implements Proxy.
var _ Proxy = (*valueProxy)(nil)

func (p *valueProxy) Nil() bool {
	return p.value == nil
}

func (p *valueProxy) Value() (interface{}, error) {
	return p.value, nil
}

func (p *valueProxy) Bool() (bool, error) {
	switch v := p.value.(type) {
	case bool:
		return v, nil
	default:
		return false, typeError(p, Tbool, v)
	}
}

type int64er interface {
	Int64() (int64, error)
}

func (p *valueProxy) Int64() (int64, error) {
	switch v := p.value.(type) {
	case int:
		return int64(v), nil
	case int32:
		return int64(v), nil
	case int64:
		return v, nil
	case float32:
		return int64(v), nil
	case float64:
		return int64(v), nil
	case int64er:
		w, err := v.Int64()
		if err != nil {
			return 0, &errorProxy{
				errorType: EconvertFailure,
				parent:    p,
				infoStr:   err.Error(),
			}
		}
		return w, nil
	default:
		return 0, typeError(p, Tint64, v)
	}
}

type float64er interface {
	Float64() (float64, error)
}

func (p *valueProxy) Float64() (float64, error) {
	switch v := p.value.(type) {
	case int:
		return float64(v), nil
	case int32:
		return float64(v), nil
	case int64:
		return float64(v), nil
	case float32:
		return float64(v), nil
	case float64:
		return v, nil
	case float64er:
		w, err := v.Float64()
		if err != nil {
			return 0, &errorProxy{
				errorType: EconvertFailure,
				parent:    p,
				infoStr:   err.Error(),
			}
		}
		return w, nil
	default:
		return 0, typeError(p, Tfloat64, v)
	}
}

func (p *valueProxy) String() (string, error) {
	switch v := p.value.(type) {
	case string:
		return v, nil
	default:
		return "", typeError(p, Tstring, v)
	}
}

func (p *valueProxy) Array() ([]interface{}, error) {
	switch v := p.value.(type) {
	case []interface{}:
		return v, nil
	default:
		return nil, typeError(p, Tarray, v)
	}
}

func (p *valueProxy) Map() (map[string]interface{}, error) {
	switch v := p.value.(type) {
	case map[string]interface{}:
		return v, nil
	default:
		return nil, typeError(p, Tmap, v)
	}
}

func (p *valueProxy) A(n int) Proxy {
	switch v := p.value.(type) {
	case []interface{}:
		a := "[" + strconv.Itoa(n) + "]"
		if n < 0 || n >= len(v) {
			return notfoundError(p, a)
		}
		return &valueProxy{
			value:  v[n],
			parent: p,
			label:  a,
		}
	default:
		return requiredTypeError(p, Tarray, v)
	}
}

var mapType = reflect.TypeOf(map[string]interface{}(nil))

func (p *valueProxy) m(v map[string]interface{}, k string) Proxy {
	a := "." + k
	w, ok := v[k]
	if !ok {
		return notfoundError(p, a)
	}
	return &valueProxy{
		value:  w,
		parent: p,
		label:  a,
	}
}

func (p *valueProxy) M(k string) Proxy {
	if v, ok := p.value.(map[string]interface{}); ok {
		return p.m(v, k)
	}

	if rv := reflect.ValueOf(p.value); rv.IsValid() && rv.Type().ConvertibleTo(mapType) {
		v, _ := rv.Convert(mapType).Interface().(map[string]interface{})
		return p.m(v, k)
	}

	return requiredTypeError(p, Tmap, p.value)
}

func (p *valueProxy) P(q string) Proxy {
	return pointer(p, q)
}

func (p *valueProxy) ProxySet() ProxySet {
	switch v := p.value.(type) {
	case []interface{}:
		return &setProxy{
			values: v,
			parent: p,
		}
	default:
		return typeError(p, Tarray, v)
	}
}

func (p *valueProxy) Q(k string) ProxySet {
	w := findAll(p.value, k)
	return &setProxy{
		values: w,
		parent: p,
		label:  ".." + k,
	}
}

func (p *valueProxy) findJPT(t string) Proxy {
	switch v := p.value.(type) {
	case map[string]interface{}:
		return p.M(t)
	case []interface{}:
		n, err := strconv.ParseUint(t, 10, 0)
		if err != nil {
			return &errorProxy{
				errorType: EinvalidIndex,
				parent:    p,
				infoStr:   err.Error(),
			}
		}
		return p.A(int(n))
	default:
		return &errorProxy{
			errorType: EmapNorArray,
			parent:    p,
			actual:    detectType(v),
		}
	}
}

func (p *valueProxy) parentFrame() frame {
	return p.parent
}

func (p *valueProxy) frameLabel() string {
	return p.label
}


================================================
FILE: value_test.go
================================================
package dproxy

import "testing"

func TestTypeError(t *testing.T) {
	t.Run("map at root", func(t *testing.T) {
		v := &valueProxy{}
		_, err := v.M("foo").Int64()
		assertError(t, err, "not required types: required=map actual=nil: (root)")
	})
	t.Run("map at child", func(t *testing.T) {
		v := &valueProxy{
			parent: &valueProxy{},
			label:  "foo",
		}
		_, err := v.M("bar").Int64()
		assertError(t, err, "not required types: required=map actual=nil: foo")
	})

	t.Run("array at root", func(t *testing.T) {
		v := &valueProxy{}
		_, err := v.A(0).Int64()
		assertError(t, err, "not required types: required=array actual=nil: (root)")
	})
	t.Run("array at child", func(t *testing.T) {
		v := &valueProxy{
			parent: &valueProxy{},
			label:  "foo",
		}
		_, err := v.A(0).Int64()
		assertError(t, err, "not required types: required=array actual=nil: foo")
	})
}
Download .txt
gitextract_caioeg4v/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       └── go.yml
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── doc.go
├── drain.go
├── drain_test.go
├── error.go
├── frame.go
├── go.mod
├── go.sum
├── package_test.go
├── pointer.go
├── pointer_test.go
├── proxy.go
├── proxy_test.go
├── set.go
├── set_test.go
├── staticcheck.conf
├── type.go
├── value.go
└── value_test.go
Download .txt
SYMBOL INDEX (141 symbols across 14 files)

FILE: drain.go
  type Drain (line 6) | type Drain struct
    method Has (line 11) | func (d *Drain) Has() bool {
    method First (line 16) | func (d *Drain) First() error {
    method All (line 24) | func (d *Drain) All() []error {
    method CombineErrors (line 34) | func (d *Drain) CombineErrors() error {
    method put (line 41) | func (d *Drain) put(err error) {
    method Bool (line 49) | func (d *Drain) Bool(p Proxy) bool {
    method Int64 (line 56) | func (d *Drain) Int64(p Proxy) int64 {
    method Float64 (line 63) | func (d *Drain) Float64(p Proxy) float64 {
    method String (line 70) | func (d *Drain) String(p Proxy) string {
    method Array (line 77) | func (d *Drain) Array(p Proxy) []interface{} {
    method Map (line 84) | func (d *Drain) Map(p Proxy) map[string]interface{} {
    method BoolArray (line 91) | func (d *Drain) BoolArray(ps ProxySet) []bool {
    method Int64Array (line 98) | func (d *Drain) Int64Array(ps ProxySet) []int64 {
    method Float64Array (line 105) | func (d *Drain) Float64Array(ps ProxySet) []float64 {
    method StringArray (line 112) | func (d *Drain) StringArray(ps ProxySet) []string {
    method ArrayArray (line 119) | func (d *Drain) ArrayArray(ps ProxySet) [][]interface{} {
    method MapArray (line 126) | func (d *Drain) MapArray(ps ProxySet) []map[string]interface{} {
    method ProxyArray (line 133) | func (d *Drain) ProxyArray(ps ProxySet) []Proxy {
  type drainError (line 139) | type drainError
    method Error (line 141) | func (derr drainError) Error() string {

FILE: drain_test.go
  function TestDrainBool (line 7) | func TestDrainBool(t *testing.T) {

FILE: error.go
  type ErrorType (line 9) | type ErrorType
    method String (line 35) | func (et ErrorType) String() string {
  constant Etype (line 13) | Etype ErrorType = iota + 1
  constant Enotfound (line 16) | Enotfound
  constant EmapNorArray (line 19) | EmapNorArray
  constant EconvertFailure (line 22) | EconvertFailure
  constant EinvalidIndex (line 25) | EinvalidIndex
  constant EinvalidQuery (line 28) | EinvalidQuery
  constant ErequiredType (line 32) | ErequiredType
  type Error (line 57) | type Error interface
  type errorProxy (line 65) | type errorProxy struct
    method Nil (line 82) | func (p *errorProxy) Nil() bool {
    method Value (line 86) | func (p *errorProxy) Value() (interface{}, error) {
    method Bool (line 90) | func (p *errorProxy) Bool() (bool, error) {
    method Int64 (line 94) | func (p *errorProxy) Int64() (int64, error) {
    method Float64 (line 98) | func (p *errorProxy) Float64() (float64, error) {
    method String (line 102) | func (p *errorProxy) String() (string, error) {
    method Array (line 106) | func (p *errorProxy) Array() ([]interface{}, error) {
    method Map (line 110) | func (p *errorProxy) Map() (map[string]interface{}, error) {
    method A (line 114) | func (p *errorProxy) A(n int) Proxy {
    method M (line 118) | func (p *errorProxy) M(k string) Proxy {
    method P (line 122) | func (p *errorProxy) P(q string) Proxy {
    method Empty (line 126) | func (p *errorProxy) Empty() bool {
    method Len (line 130) | func (p *errorProxy) Len() int {
    method BoolArray (line 134) | func (p *errorProxy) BoolArray() ([]bool, error) {
    method Int64Array (line 138) | func (p *errorProxy) Int64Array() ([]int64, error) {
    method Float64Array (line 142) | func (p *errorProxy) Float64Array() ([]float64, error) {
    method StringArray (line 146) | func (p *errorProxy) StringArray() ([]string, error) {
    method ArrayArray (line 150) | func (p *errorProxy) ArrayArray() ([][]interface{}, error) {
    method MapArray (line 154) | func (p *errorProxy) MapArray() ([]map[string]interface{}, error) {
    method ProxyArray (line 158) | func (p *errorProxy) ProxyArray() ([]Proxy, error) {
    method ProxySet (line 162) | func (p *errorProxy) ProxySet() ProxySet {
    method Q (line 166) | func (p *errorProxy) Q(k string) ProxySet {
    method Qc (line 170) | func (p *errorProxy) Qc(k string) ProxySet {
    method findJPT (line 174) | func (p *errorProxy) findJPT(t string) Proxy {
    method parentFrame (line 178) | func (p *errorProxy) parentFrame() frame {
    method frameLabel (line 182) | func (p *errorProxy) frameLabel() string {
    method Error (line 186) | func (p *errorProxy) Error() string {
    method ErrorType (line 213) | func (p *errorProxy) ErrorType() ErrorType {
    method FullAddress (line 217) | func (p *errorProxy) FullAddress() string {
  function typeError (line 221) | func typeError(p frame, expected Type, actual interface{}) *errorProxy {
  function requiredTypeError (line 230) | func requiredTypeError(p frame, expected Type, actual interface{}) *erro...
  function elementTypeError (line 239) | func elementTypeError(p frame, index int, expected Type, actual interfac...
  function notfoundError (line 247) | func notfoundError(p frame, address string) *errorProxy {

FILE: frame.go
  type frame (line 3) | type frame interface
  function fullAddress (line 10) | func fullAddress(f frame) string {
  type simpleFrame (line 29) | type simpleFrame struct
    method parentFrame (line 36) | func (f *simpleFrame) parentFrame() frame {
    method frameLabel (line 40) | func (f *simpleFrame) frameLabel() string {

FILE: package_test.go
  function assertEquals (line 9) | func assertEquals(t *testing.T, actual, expected interface{}, format str...
  function assertError (line 17) | func assertError(t *testing.T, err error, exp string) {

FILE: pointer.go
  function unescapeJPT (line 7) | func unescapeJPT(t string) string {
  function pointer (line 11) | func pointer(p Proxy, q string) Proxy {
  function Pointer (line 29) | func Pointer(v interface{}, q string) Proxy {

FILE: pointer_test.go
  function TestUnescapeJPT (line 5) | func TestUnescapeJPT(t *testing.T) {
  function TestPointerInvalidQuery (line 23) | func TestPointerInvalidQuery(t *testing.T) {
  function TestPointer (line 34) | func TestPointer(t *testing.T) {

FILE: proxy.go
  type Proxy (line 4) | type Proxy interface
  type ProxySet (line 53) | type ProxySet interface
  function New (line 95) | func New(v interface{}) Proxy {
  function NewSet (line 100) | func NewSet(v []interface{}) ProxySet {

FILE: proxy_test.go
  function parseJSON (line 8) | func parseJSON(s string) interface{} {
  function equalStrings (line 16) | func equalStrings(a, b []string) bool {
  function equalInts (line 28) | func equalInts(a, b []int64) bool {
  function TestReadme (line 40) | func TestReadme(t *testing.T) {
  function TestMapBool (line 74) | func TestMapBool(t *testing.T) {
  type wrappedMap (line 97) | type wrappedMap
  function TestWrappedMap (line 99) | func TestWrappedMap(t *testing.T) {

FILE: set.go
  type setProxy (line 5) | type setProxy struct
    method Empty (line 14) | func (p *setProxy) Empty() bool {
    method Len (line 18) | func (p *setProxy) Len() int {
    method BoolArray (line 22) | func (p *setProxy) BoolArray() ([]bool, error) {
    method Int64Array (line 35) | func (p *setProxy) Int64Array() ([]int64, error) {
    method Float64Array (line 56) | func (p *setProxy) Float64Array() ([]float64, error) {
    method StringArray (line 77) | func (p *setProxy) StringArray() ([]string, error) {
    method ArrayArray (line 90) | func (p *setProxy) ArrayArray() ([][]interface{}, error) {
    method MapArray (line 103) | func (p *setProxy) MapArray() ([]map[string]interface{}, error) {
    method ProxyArray (line 116) | func (p *setProxy) ProxyArray() ([]Proxy, error) {
    method A (line 128) | func (p *setProxy) A(n int) Proxy {
    method Q (line 140) | func (p *setProxy) Q(k string) ProxySet {
    method Qc (line 149) | func (p *setProxy) Qc(k string) ProxySet {
    method parentFrame (line 166) | func (p *setProxy) parentFrame() frame {
    method frameLabel (line 170) | func (p *setProxy) frameLabel() string {
  function findAll (line 174) | func findAll(v interface{}, k string) []interface{} {
  function findAllImpl (line 178) | func findAllImpl(v interface{}, k string, r []interface{}) []interface{} {

FILE: set_test.go
  function TestSet (line 5) | func TestSet(t *testing.T) {
  function TestSetTypeError (line 39) | func TestSetTypeError(t *testing.T) {

FILE: type.go
  type Type (line 4) | type Type
    method String (line 55) | func (t Type) String() string {
  constant Tunknown (line 8) | Tunknown Type = iota
  constant Tnil (line 11) | Tnil
  constant Tbool (line 14) | Tbool
  constant Tint64 (line 17) | Tint64
  constant Tfloat64 (line 20) | Tfloat64
  constant Tstring (line 23) | Tstring
  constant Tarray (line 26) | Tarray
  constant Tmap (line 29) | Tmap
  function detectType (line 33) | func detectType(v interface{}) Type {

FILE: value.go
  type valueProxy (line 8) | type valueProxy struct
    method Nil (line 17) | func (p *valueProxy) Nil() bool {
    method Value (line 21) | func (p *valueProxy) Value() (interface{}, error) {
    method Bool (line 25) | func (p *valueProxy) Bool() (bool, error) {
    method Int64 (line 38) | func (p *valueProxy) Int64() (int64, error) {
    method Float64 (line 69) | func (p *valueProxy) Float64() (float64, error) {
    method String (line 96) | func (p *valueProxy) String() (string, error) {
    method Array (line 105) | func (p *valueProxy) Array() ([]interface{}, error) {
    method Map (line 114) | func (p *valueProxy) Map() (map[string]interface{}, error) {
    method A (line 123) | func (p *valueProxy) A(n int) Proxy {
    method m (line 142) | func (p *valueProxy) m(v map[string]interface{}, k string) Proxy {
    method M (line 155) | func (p *valueProxy) M(k string) Proxy {
    method P (line 168) | func (p *valueProxy) P(q string) Proxy {
    method ProxySet (line 172) | func (p *valueProxy) ProxySet() ProxySet {
    method Q (line 184) | func (p *valueProxy) Q(k string) ProxySet {
    method findJPT (line 193) | func (p *valueProxy) findJPT(t string) Proxy {
    method parentFrame (line 216) | func (p *valueProxy) parentFrame() frame {
    method frameLabel (line 220) | func (p *valueProxy) frameLabel() string {
  type int64er (line 34) | type int64er interface
  type float64er (line 65) | type float64er interface

FILE: value_test.go
  function TestTypeError (line 5) | func TestTypeError(t *testing.T) {
Condensed preview — 24 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (46K chars).
[
  {
    "path": ".github/dependabot.yml",
    "chars": 580,
    "preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
  },
  {
    "path": ".github/workflows/go.yml",
    "chars": 5638,
    "preview": "name: Go\n\non: [push]\n\npermissions:\n  contents: write\n\nenv:\n  GO_VERSION: 'oldstable'\n\njobs:\n\n  check:\n    name: Check ma"
  },
  {
    "path": ".gitignore",
    "chars": 12,
    "preview": "/tags\n/tmp/\n"
  },
  {
    "path": "LICENSE",
    "chars": 1105,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015 MURAOKA Taro <koron.kaoriya@gmail.com>\n\nPermission is hereby granted, free of "
  },
  {
    "path": "Makefile",
    "chars": 1717,
    "preview": "# Get relative paths of all \"main\" packages\nMAIN_PACKAGE ?= $(shell go list -f '{{if (eq .Name \"main\")}}.{{slice .Import"
  },
  {
    "path": "README.md",
    "chars": 3395,
    "preview": "# dProxy - document proxy\n\n[![GoDoc](https://godoc.org/github.com/koron/go-dproxy?status.svg)](https://godoc.org/github."
  },
  {
    "path": "doc.go",
    "chars": 175,
    "preview": "/*\nPackage dproxy provides a proxy to adccess `interface{}` (document) by simple\nquery.  It is intended to be used with "
  },
  {
    "path": "drain.go",
    "chars": 3232,
    "preview": "package dproxy\n\nimport \"bytes\"\n\n// Drain stores errors from Proxy or ProxySet.\ntype Drain struct {\n\terrors []error\n}\n\n//"
  },
  {
    "path": "drain_test.go",
    "chars": 613,
    "preview": "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\": fal"
  },
  {
    "path": "error.go",
    "chars": 5175,
    "preview": "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"
  },
  {
    "path": "frame.go",
    "chars": 723,
    "preview": "package dproxy\n\ntype frame interface {\n\t// parentFrame returns parent frame.\n\tparentFrame() frame\n\t// frameLabel return "
  },
  {
    "path": "go.mod",
    "chars": 43,
    "preview": "module github.com/koron/go-dproxy\n\ngo 1.13\n"
  },
  {
    "path": "go.sum",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "package_test.go",
    "chars": 561,
    "preview": "package dproxy\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc assertEquals(t *testing.T, actual, expected interface{}, f"
  },
  {
    "path": "pointer.go",
    "chars": 589,
    "preview": "package dproxy\n\nimport \"strings\"\n\nvar jptR = strings.NewReplacer(\"~1\", \"/\", \"~0\", \"~\")\n\nfunc unescapeJPT(t string) strin"
  },
  {
    "path": "pointer_test.go",
    "chars": 1953,
    "preview": "package dproxy\n\nimport \"testing\"\n\nfunc TestUnescapeJPT(t *testing.T) {\n\tf := func(d, expect string) {\n\t\ts := unescapeJPT"
  },
  {
    "path": "proxy.go",
    "chars": 2756,
    "preview": "package dproxy\n\n// Proxy is a proxy to access a document (interface{}).\ntype Proxy interface {\n\t// Nil returns true, if "
  },
  {
    "path": "proxy_test.go",
    "chars": 1964,
    "preview": "package dproxy\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n)\n\nfunc parseJSON(s string) interface{} {\n\tvar v interface{}\n\tif er"
  },
  {
    "path": "set.go",
    "chars": 3606,
    "preview": "package dproxy\n\nimport \"strconv\"\n\ntype setProxy struct {\n\tvalues []interface{}\n\tparent frame\n\tlabel  string\n}\n\n// setPro"
  },
  {
    "path": "set_test.go",
    "chars": 1025,
    "preview": "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"
  },
  {
    "path": "staticcheck.conf",
    "chars": 163,
    "preview": "# vim:set ft=toml:\n\nchecks = [\"all\"]\n\n# based on: github.com/koron-go/_skeleton/staticcheck.conf\n# $Hash:cd6871e83e780f6"
  },
  {
    "path": "type.go",
    "chars": 1175,
    "preview": "package dproxy\n\n// Type is type of value.\ntype Type int\n\nconst (\n\t// Tunknown shows value is not supported.\n\tTunknown Ty"
  },
  {
    "path": "value.go",
    "chars": 4004,
    "preview": "package dproxy\n\nimport (\n\t\"reflect\"\n\t\"strconv\"\n)\n\ntype valueProxy struct {\n\tvalue  interface{}\n\tparent frame\n\tlabel  str"
  },
  {
    "path": "value_test.go",
    "chars": 866,
    "preview": "package dproxy\n\nimport \"testing\"\n\nfunc TestTypeError(t *testing.T) {\n\tt.Run(\"map at root\", func(t *testing.T) {\n\t\tv := &"
  }
]

About this extraction

This page contains the full source code of the koron/go-dproxy GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 24 files (40.1 KB), approximately 13.0k tokens, and a symbol index with 141 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!