├── scripts
└── test.sh
├── vendor
└── github.com
│ ├── kr
│ ├── pretty
│ │ ├── .gitignore
│ │ ├── Readme
│ │ ├── example_test.go
│ │ ├── License
│ │ ├── zero.go
│ │ ├── pretty.go
│ │ ├── formatter_test.go
│ │ ├── diff.go
│ │ ├── diff_test.go
│ │ └── formatter.go
│ └── text
│ │ ├── doc.go
│ │ ├── Readme
│ │ ├── colwriter
│ │ ├── Readme
│ │ ├── column_test.go
│ │ └── column.go
│ │ ├── mc
│ │ ├── Readme
│ │ └── mc.go
│ │ ├── License
│ │ ├── wrap_test.go
│ │ ├── indent.go
│ │ ├── cmd
│ │ └── agg
│ │ │ ├── string.go
│ │ │ ├── num.go
│ │ │ ├── main.go
│ │ │ └── doc.go
│ │ ├── wrap.go
│ │ └── indent_test.go
│ ├── koki
│ └── structurederrors
│ │ ├── glide.yaml
│ │ ├── glide.lock
│ │ ├── error.go
│ │ └── LICENSE
│ └── golang
│ └── glog
│ ├── README
│ ├── glog_file.go
│ ├── LICENSE
│ └── glog_test.go
├── testdata
└── code.json.gz
├── glide.yaml
├── glide.lock
├── tags_test.go
├── jsonutil
├── path.go
├── obj_test.go
└── obj.go
├── tags.go
├── LICENSE.txt
├── example_marshaling_test.go
├── README.md
├── number_test.go
├── tagkey_test.go
├── fold_test.go
├── indent.go
├── fold.go
├── tables.go
├── bench_test.go
├── example_test.go
├── scanner_test.go
├── stream_test.go
├── stream.go
└── scanner.go
/scripts/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | go test $(glide novendor)
3 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/pretty/.gitignore:
--------------------------------------------------------------------------------
1 | [568].out
2 | _go*
3 | _test*
4 | _obj
5 |
--------------------------------------------------------------------------------
/testdata/code.json.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/koki/json/HEAD/testdata/code.json.gz
--------------------------------------------------------------------------------
/glide.yaml:
--------------------------------------------------------------------------------
1 | package: github.com/koki/json
2 | import:
3 | - package: github.com/koki/structurederrors
4 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/doc.go:
--------------------------------------------------------------------------------
1 | // Package text provides rudimentary functions for manipulating text in
2 | // paragraphs.
3 | package text
4 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/Readme:
--------------------------------------------------------------------------------
1 | This is a Go package for manipulating paragraphs of text.
2 |
3 | See http://go.pkgdoc.org/github.com/kr/text for full documentation.
4 |
--------------------------------------------------------------------------------
/vendor/github.com/koki/structurederrors/glide.yaml:
--------------------------------------------------------------------------------
1 | package: github.com/koki/structurederrors
2 | import:
3 | - package: github.com/golang/glog
4 | - package: github.com/kr/pretty
5 | - package: github.com/kr/text
6 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/pretty/Readme:
--------------------------------------------------------------------------------
1 | package pretty
2 |
3 | import "github.com/kr/pretty"
4 |
5 | Package pretty provides pretty-printing for Go values.
6 |
7 | Documentation
8 |
9 | http://godoc.org/github.com/kr/pretty
10 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/colwriter/Readme:
--------------------------------------------------------------------------------
1 | Package colwriter provides a write filter that formats
2 | input lines in multiple columns.
3 |
4 | The package is a straightforward translation from
5 | /src/cmd/draw/mc.c in Plan 9 from User Space.
6 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/mc/Readme:
--------------------------------------------------------------------------------
1 | Command mc prints in multiple columns.
2 |
3 | Usage: mc [-] [-N] [file...]
4 |
5 | Mc splits the input into as many columns as will fit in N
6 | print positions. If the output is a tty, the default N is
7 | the number of characters in a terminal line; otherwise the
8 | default N is 80. Under option - each input line ending in
9 | a colon ':' is printed separately.
10 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/pretty/example_test.go:
--------------------------------------------------------------------------------
1 | package pretty_test
2 |
3 | import (
4 | "fmt"
5 | "github.com/kr/pretty"
6 | )
7 |
8 | func Example() {
9 | type myType struct {
10 | a, b int
11 | }
12 | var x = []myType{{1, 2}, {3, 4}, {5, 6}}
13 | fmt.Printf("%# v", pretty.Formatter(x))
14 | // output:
15 | // []pretty_test.myType{
16 | // {a:1, b:2},
17 | // {a:3, b:4},
18 | // {a:5, b:6},
19 | // }
20 | }
21 |
--------------------------------------------------------------------------------
/vendor/github.com/koki/structurederrors/glide.lock:
--------------------------------------------------------------------------------
1 | hash: dda6d31b252c37921f4ce07c47f20b2694accff9ccfa0b19fc3edfe5a38f7ef5
2 | updated: 2017-12-11T23:38:19.285133981-08:00
3 | imports:
4 | - name: github.com/golang/glog
5 | version: 23def4e6c14b4da8ac2ed8007337bc5eb5007998
6 | - name: github.com/kr/pretty
7 | version: cfb55aafdaf3ec08f0db22699ab822c50091b1c4
8 | - name: github.com/kr/text
9 | version: 7cafcd837844e784b526369c9bce262804aebc60
10 | testImports: []
11 |
--------------------------------------------------------------------------------
/glide.lock:
--------------------------------------------------------------------------------
1 | hash: a03673a1b9c3168b7f254eb4a43ebd2ce0bfd383c4b0febb9c17c735207c739c
2 | updated: 2017-12-11T23:41:24.347981893-08:00
3 | imports:
4 | - name: github.com/golang/glog
5 | version: 23def4e6c14b4da8ac2ed8007337bc5eb5007998
6 | - name: github.com/koki/structurederrors
7 | version: 5a728381eca193d3a3c364256d01295346519936
8 | - name: github.com/kr/pretty
9 | version: cfb55aafdaf3ec08f0db22699ab822c50091b1c4
10 | - name: github.com/kr/text
11 | version: 7cafcd837844e784b526369c9bce262804aebc60
12 | testImports: []
13 |
--------------------------------------------------------------------------------
/tags_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package json
6 |
7 | import (
8 | "testing"
9 | )
10 |
11 | func TestTagParsing(t *testing.T) {
12 | name, opts := parseTag("field,foobar,foo")
13 | if name != "field" {
14 | t.Fatalf("name = %q, want field", name)
15 | }
16 | for _, tt := range []struct {
17 | opt string
18 | want bool
19 | }{
20 | {"foobar", true},
21 | {"foo", true},
22 | {"bar", false},
23 | } {
24 | if opts.Contains(tt.opt) != tt.want {
25 | t.Errorf("Contains(%q) = %v", tt.opt, !tt.want)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/License:
--------------------------------------------------------------------------------
1 | Copyright 2012 Keith Rarick
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/pretty/License:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright 2012 Keith Rarick
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/jsonutil/path.go:
--------------------------------------------------------------------------------
1 | package jsonutil
2 |
3 | import (
4 | "strconv"
5 |
6 | serrors "github.com/koki/structurederrors"
7 | )
8 |
9 | func AtPathIn(obj interface{}, path []string) (interface{}, error) {
10 | if len(path) == 0 {
11 | return obj, nil
12 | }
13 |
14 | key := path[0]
15 | remainder := path[1:]
16 | switch obj := obj.(type) {
17 | case []interface{}:
18 | i, err := strconv.ParseInt(key, 10, 64)
19 | if err != nil {
20 | return nil, serrors.ContextualizeErrorf(err, key)
21 | }
22 | if len(obj) <= int(i) {
23 | return nil, serrors.InvalidValueErrorf(i, "index not found")
24 | }
25 |
26 | val, err := AtPathIn(obj[i], remainder)
27 | if err != nil {
28 | return nil, serrors.ContextualizeErrorf(err, key)
29 | }
30 | return val, nil
31 | case map[string]interface{}:
32 | if val, ok := obj[key]; ok {
33 | val, err := AtPathIn(val, remainder)
34 | if err != nil {
35 | return nil, serrors.ContextualizeErrorf(err, key)
36 | }
37 | return val, nil
38 | }
39 | return nil, serrors.InvalidValueErrorf(key, "key not found")
40 | default:
41 | return nil, serrors.InvalidValueErrorf(key, "can only index into slice or map")
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/pretty/zero.go:
--------------------------------------------------------------------------------
1 | package pretty
2 |
3 | import (
4 | "reflect"
5 | )
6 |
7 | func nonzero(v reflect.Value) bool {
8 | switch v.Kind() {
9 | case reflect.Bool:
10 | return v.Bool()
11 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
12 | return v.Int() != 0
13 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
14 | return v.Uint() != 0
15 | case reflect.Float32, reflect.Float64:
16 | return v.Float() != 0
17 | case reflect.Complex64, reflect.Complex128:
18 | return v.Complex() != complex(0, 0)
19 | case reflect.String:
20 | return v.String() != ""
21 | case reflect.Struct:
22 | for i := 0; i < v.NumField(); i++ {
23 | if nonzero(getField(v, i)) {
24 | return true
25 | }
26 | }
27 | return false
28 | case reflect.Array:
29 | for i := 0; i < v.Len(); i++ {
30 | if nonzero(v.Index(i)) {
31 | return true
32 | }
33 | }
34 | return false
35 | case reflect.Map, reflect.Interface, reflect.Slice, reflect.Ptr, reflect.Chan, reflect.Func:
36 | return !v.IsNil()
37 | case reflect.UnsafePointer:
38 | return v.Pointer() != 0
39 | }
40 | return true
41 | }
42 |
--------------------------------------------------------------------------------
/tags.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package json
6 |
7 | import (
8 | "strings"
9 | )
10 |
11 | // tagOptions is the string following a comma in a struct field's "json"
12 | // tag, or the empty string. It does not include the leading comma.
13 | type tagOptions string
14 |
15 | // parseTag splits a struct field's json tag into its name and
16 | // comma-separated options.
17 | func parseTag(tag string) (string, tagOptions) {
18 | if idx := strings.Index(tag, ","); idx != -1 {
19 | return tag[:idx], tagOptions(tag[idx+1:])
20 | }
21 | return tag, tagOptions("")
22 | }
23 |
24 | // Contains reports whether a comma-separated list of options
25 | // contains a particular substr flag. substr must be surrounded by a
26 | // string boundary or commas.
27 | func (o tagOptions) Contains(optionName string) bool {
28 | if len(o) == 0 {
29 | return false
30 | }
31 | s := string(o)
32 | for s != "" {
33 | var next string
34 | i := strings.Index(s, ",")
35 | if i >= 0 {
36 | s, next = s[:i], s[i+1:]
37 | }
38 | if s == optionName {
39 | return true
40 | }
41 | s = next
42 | }
43 | return false
44 | }
45 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/wrap_test.go:
--------------------------------------------------------------------------------
1 | package text
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 | )
7 |
8 | var text = "The quick brown fox jumps over the lazy dog."
9 |
10 | func TestWrap(t *testing.T) {
11 | exp := [][]string{
12 | {"The", "quick", "brown", "fox"},
13 | {"jumps", "over", "the", "lazy", "dog."},
14 | }
15 | words := bytes.Split([]byte(text), sp)
16 | got := WrapWords(words, 1, 24, defaultPenalty)
17 | if len(exp) != len(got) {
18 | t.Fail()
19 | }
20 | for i := range exp {
21 | if len(exp[i]) != len(got[i]) {
22 | t.Fail()
23 | }
24 | for j := range exp[i] {
25 | if exp[i][j] != string(got[i][j]) {
26 | t.Fatal(i, exp[i][j], got[i][j])
27 | }
28 | }
29 | }
30 | }
31 |
32 | func TestWrapNarrow(t *testing.T) {
33 | exp := "The\nquick\nbrown\nfox\njumps\nover\nthe\nlazy\ndog."
34 | if Wrap(text, 5) != exp {
35 | t.Fail()
36 | }
37 | }
38 |
39 | func TestWrapOneLine(t *testing.T) {
40 | exp := "The quick brown fox jumps over the lazy dog."
41 | if Wrap(text, 500) != exp {
42 | t.Fail()
43 | }
44 | }
45 |
46 | func TestWrapBug1(t *testing.T) {
47 | cases := []struct {
48 | limit int
49 | text string
50 | want string
51 | }{
52 | {4, "aaaaa", "aaaaa"},
53 | {4, "a aaaaa", "a\naaaaa"},
54 | }
55 |
56 | for _, test := range cases {
57 | got := Wrap(test.text, test.limit)
58 | if got != test.want {
59 | t.Errorf("Wrap(%q, %d) = %q want %q", test.text, test.limit, got, test.want)
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/mc/mc.go:
--------------------------------------------------------------------------------
1 | // Command mc prints in multiple columns.
2 | //
3 | // Usage: mc [-] [-N] [file...]
4 | //
5 | // Mc splits the input into as many columns as will fit in N
6 | // print positions. If the output is a tty, the default N is
7 | // the number of characters in a terminal line; otherwise the
8 | // default N is 80. Under option - each input line ending in
9 | // a colon ':' is printed separately.
10 | package main
11 |
12 | import (
13 | "github.com/kr/pty"
14 | "github.com/kr/text/colwriter"
15 | "io"
16 | "log"
17 | "os"
18 | "strconv"
19 | )
20 |
21 | func main() {
22 | var width int
23 | var flag uint
24 | args := os.Args[1:]
25 | for len(args) > 0 && len(args[0]) > 0 && args[0][0] == '-' {
26 | if len(args[0]) > 1 {
27 | width, _ = strconv.Atoi(args[0][1:])
28 | } else {
29 | flag |= colwriter.BreakOnColon
30 | }
31 | args = args[1:]
32 | }
33 | if width < 1 {
34 | _, width, _ = pty.Getsize(os.Stdout)
35 | }
36 | if width < 1 {
37 | width = 80
38 | }
39 |
40 | w := colwriter.NewWriter(os.Stdout, width, flag)
41 | if len(args) > 0 {
42 | for _, s := range args {
43 | if f, err := os.Open(s); err == nil {
44 | copyin(w, f)
45 | f.Close()
46 | } else {
47 | log.Println(err)
48 | }
49 | }
50 | } else {
51 | copyin(w, os.Stdin)
52 | }
53 | }
54 |
55 | func copyin(w *colwriter.Writer, r io.Reader) {
56 | if _, err := io.Copy(w, r); err != nil {
57 | log.Println(err)
58 | }
59 | if err := w.Flush(); err != nil {
60 | log.Println(err)
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/vendor/github.com/golang/glog/README:
--------------------------------------------------------------------------------
1 | glog
2 | ====
3 |
4 | Leveled execution logs for Go.
5 |
6 | This is an efficient pure Go implementation of leveled logs in the
7 | manner of the open source C++ package
8 | https://github.com/google/glog
9 |
10 | By binding methods to booleans it is possible to use the log package
11 | without paying the expense of evaluating the arguments to the log.
12 | Through the -vmodule flag, the package also provides fine-grained
13 | control over logging at the file level.
14 |
15 | The comment from glog.go introduces the ideas:
16 |
17 | Package glog implements logging analogous to the Google-internal
18 | C++ INFO/ERROR/V setup. It provides functions Info, Warning,
19 | Error, Fatal, plus formatting variants such as Infof. It
20 | also provides V-style logging controlled by the -v and
21 | -vmodule=file=2 flags.
22 |
23 | Basic examples:
24 |
25 | glog.Info("Prepare to repel boarders")
26 |
27 | glog.Fatalf("Initialization failed: %s", err)
28 |
29 | See the documentation for the V function for an explanation
30 | of these examples:
31 |
32 | if glog.V(2) {
33 | glog.Info("Starting transaction...")
34 | }
35 |
36 | glog.V(2).Infoln("Processed", nItems, "elements")
37 |
38 |
39 | The repository contains an open source version of the log package
40 | used inside Google. The master copy of the source lives inside
41 | Google, not here. The code in this repo is for export only and is not itself
42 | under development. Feature requests will be ignored.
43 |
44 | Send bug reports to golang-nuts@googlegroups.com.
45 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009 The Go Authors. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above
10 | copyright notice, this list of conditions and the following disclaimer
11 | in the documentation and/or other materials provided with the
12 | distribution.
13 | * Neither the name of Google Inc. nor the names of its
14 | contributors may be used to endorse or promote products derived from
15 | this software without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/example_marshaling_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2016 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package json_test
6 |
7 | import (
8 | "fmt"
9 | "log"
10 | "strings"
11 |
12 | "github.com/koki/json"
13 | )
14 |
15 | type Animal int
16 |
17 | const (
18 | Unknown Animal = iota
19 | Gopher
20 | Zebra
21 | )
22 |
23 | func (a *Animal) UnmarshalJSON(b []byte) error {
24 | var s string
25 | if err := json.Unmarshal(b, &s); err != nil {
26 | return err
27 | }
28 | switch strings.ToLower(s) {
29 | default:
30 | *a = Unknown
31 | case "gopher":
32 | *a = Gopher
33 | case "zebra":
34 | *a = Zebra
35 | }
36 |
37 | return nil
38 | }
39 |
40 | func (a Animal) MarshalJSON() ([]byte, error) {
41 | var s string
42 | switch a {
43 | default:
44 | s = "unknown"
45 | case Gopher:
46 | s = "gopher"
47 | case Zebra:
48 | s = "zebra"
49 | }
50 |
51 | return json.Marshal(s)
52 | }
53 |
54 | func Example_customMarshalJSON() {
55 | blob := `["gopher","armadillo","zebra","unknown","gopher","bee","gopher","zebra"]`
56 | var zoo []Animal
57 | if err := json.Unmarshal([]byte(blob), &zoo); err != nil {
58 | log.Fatal(err)
59 | }
60 |
61 | census := make(map[Animal]int)
62 | for _, animal := range zoo {
63 | census[animal] += 1
64 | }
65 |
66 | fmt.Printf("Zoo Census:\n* Gophers: %d\n* Zebras: %d\n* Unknown: %d\n",
67 | census[Gopher], census[Zebra], census[Unknown])
68 |
69 | // Output:
70 | // Zoo Census:
71 | // * Gophers: 3
72 | // * Zebras: 2
73 | // * Unknown: 3
74 | }
75 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Koki's JSON library
2 |
3 | It's a fork that makes `encoding/json` better for users.
4 |
5 | ## Features
6 |
7 | * Annotates decoder errors with the path (e.g. `$.pod.container.0.env`) where the error occurred. _The golang built-in implementation doesn't contextualize errors, so it's hard to track down where they came from._
8 |
9 | * Check for extraneous fields in your JSON, which is useful for detecting misspelled keys and other typos.
10 |
11 | * `omitempty` actually omits zero-valued structs.
12 |
13 | ## How to use it
14 |
15 | `github.com/koki/json` is a drop-in replacement for `encoding/json`. The decoder implementation is different, but the library API remains unchanged. Use this package's `json.Unmarshal` if you want paths for your decoder errors. Use `json.Marshal` if you want to omit zero-valued structs.
16 |
17 | ```go
18 | // Deserialize
19 | foo := Foo{}
20 | err := json.Unmarshal(data, &foo)
21 | ...
22 |
23 | // Serialize
24 | bar := Bar{}
25 | data, err := json.Marshal(bar)
26 | ...
27 | ```
28 |
29 | `github.com/koki/json/jsonutil` is a brand-new package. Use `jsonutil.ExtraneousFieldPaths` to get a list of paths that weren't decoded into your Go object. i.e. potential typos.
30 |
31 | ```go
32 | // 1. Parse.
33 | obj := make(map[string]interface{})
34 | parsedObj := Foo{}
35 | err := json.Unmarshal(data, &obj)
36 | ...
37 | err = jsonutil.UnmarshalMap(obj, &parsedObj)
38 | ...
39 |
40 | // 2. Check for unparsed fields--potential typos.
41 | extraneousPaths, err := jsonutil.ExtraneousFieldPaths(obj, parsedObj)
42 | ...
43 | if len(extraneousPaths) > 0 {
44 | return nil, &jsonutil.ExtraneousFieldsError{Paths: extraneousPaths}
45 | }
46 | ...
47 | ```
48 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/indent.go:
--------------------------------------------------------------------------------
1 | package text
2 |
3 | import (
4 | "io"
5 | )
6 |
7 | // Indent inserts prefix at the beginning of each non-empty line of s. The
8 | // end-of-line marker is NL.
9 | func Indent(s, prefix string) string {
10 | return string(IndentBytes([]byte(s), []byte(prefix)))
11 | }
12 |
13 | // IndentBytes inserts prefix at the beginning of each non-empty line of b.
14 | // The end-of-line marker is NL.
15 | func IndentBytes(b, prefix []byte) []byte {
16 | var res []byte
17 | bol := true
18 | for _, c := range b {
19 | if bol && c != '\n' {
20 | res = append(res, prefix...)
21 | }
22 | res = append(res, c)
23 | bol = c == '\n'
24 | }
25 | return res
26 | }
27 |
28 | // Writer indents each line of its input.
29 | type indentWriter struct {
30 | w io.Writer
31 | bol bool
32 | pre [][]byte
33 | sel int
34 | off int
35 | }
36 |
37 | // NewIndentWriter makes a new write filter that indents the input
38 | // lines. Each line is prefixed in order with the corresponding
39 | // element of pre. If there are more lines than elements, the last
40 | // element of pre is repeated for each subsequent line.
41 | func NewIndentWriter(w io.Writer, pre ...[]byte) io.Writer {
42 | return &indentWriter{
43 | w: w,
44 | pre: pre,
45 | bol: true,
46 | }
47 | }
48 |
49 | // The only errors returned are from the underlying indentWriter.
50 | func (w *indentWriter) Write(p []byte) (n int, err error) {
51 | for _, c := range p {
52 | if w.bol {
53 | var i int
54 | i, err = w.w.Write(w.pre[w.sel][w.off:])
55 | w.off += i
56 | if err != nil {
57 | return n, err
58 | }
59 | }
60 | _, err = w.w.Write([]byte{c})
61 | if err != nil {
62 | return n, err
63 | }
64 | n++
65 | w.bol = c == '\n'
66 | if w.bol {
67 | w.off = 0
68 | if w.sel < len(w.pre)-1 {
69 | w.sel++
70 | }
71 | }
72 | }
73 | return n, nil
74 | }
75 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/cmd/agg/string.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "math/rand"
5 | "strings"
6 | )
7 |
8 | func first(s, arg string) agg { return &sbinop{s, opfirst} }
9 | func last(s, arg string) agg { return &sbinop{s, oplast} }
10 | func prefix(s, arg string) agg { return &sbinop{s, opprefix} }
11 | func join(s, arg string) agg { return &sbinop{s, opjoin(arg)} }
12 | func smin(s, arg string) agg { return &sbinop{s, opsmin} }
13 | func smax(s, arg string) agg { return &sbinop{s, opsmax} }
14 |
15 | type sbinop struct {
16 | s string
17 | f func(a, b string) string
18 | }
19 |
20 | func (o *sbinop) String() string { return o.s }
21 |
22 | func (o *sbinop) merge(s string) { o.s = o.f(o.s, s) }
23 |
24 | func opfirst(a, b string) string { return a }
25 | func oplast(a, b string) string { return b }
26 |
27 | func opprefix(a, b string) string {
28 | for i := range a {
29 | if i >= len(b) || a[i] != b[i] {
30 | return a[:i]
31 | }
32 | }
33 | return a
34 | }
35 |
36 | func opjoin(sep string) func(a, b string) string {
37 | return func(a, b string) string {
38 | return a + sep + b // TODO(kr): too slow? maybe strings.Join?
39 | }
40 | }
41 |
42 | func opsmin(a, b string) string {
43 | if strings.Compare(a, b) <= 0 {
44 | return a
45 | }
46 | return b
47 | }
48 |
49 | func opsmax(a, b string) string {
50 | if strings.Compare(a, b) >= 0 {
51 | return a
52 | }
53 | return b
54 | }
55 |
56 | type sampler struct {
57 | n int
58 | s string
59 | }
60 |
61 | func sample(s, arg string) agg { return &sampler{1, s} }
62 | func (p *sampler) String() string { return p.s }
63 | func (p *sampler) merge(s string) {
64 | p.n++
65 | if rand.Intn(p.n) == 0 {
66 | p.s = s
67 | }
68 | }
69 |
70 | type constant string
71 |
72 | func constf(init, arg string) agg { return constant(arg) }
73 | func (c constant) String() string { return string(c) }
74 | func (c constant) merge(string) {}
75 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/colwriter/column_test.go:
--------------------------------------------------------------------------------
1 | package colwriter
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 | )
7 |
8 | var src = `
9 | .git
10 | .gitignore
11 | .godir
12 | Procfile:
13 | README.md
14 | api.go
15 | apps.go
16 | auth.go
17 | darwin.go
18 | data.go
19 | dyno.go:
20 | env.go
21 | git.go
22 | help.go
23 | hkdist
24 | linux.go
25 | ls.go
26 | main.go
27 | plugin.go
28 | run.go
29 | scale.go
30 | ssh.go
31 | tail.go
32 | term
33 | unix.go
34 | update.go
35 | version.go
36 | windows.go
37 | `[1:]
38 |
39 | var tests = []struct {
40 | wid int
41 | flag uint
42 | src string
43 | want string
44 | }{
45 | {80, 0, "", ""},
46 | {80, 0, src, `
47 | .git README.md darwin.go git.go ls.go scale.go unix.go
48 | .gitignore api.go data.go help.go main.go ssh.go update.go
49 | .godir apps.go dyno.go: hkdist plugin.go tail.go version.go
50 | Procfile: auth.go env.go linux.go run.go term windows.go
51 | `[1:]},
52 | {80, BreakOnColon, src, `
53 | .git .gitignore .godir
54 |
55 | Procfile:
56 | README.md api.go apps.go auth.go darwin.go data.go
57 |
58 | dyno.go:
59 | env.go hkdist main.go scale.go term version.go
60 | git.go linux.go plugin.go ssh.go unix.go windows.go
61 | help.go ls.go run.go tail.go update.go
62 | `[1:]},
63 | {20, 0, `
64 | Hello
65 | Γειά σου
66 | 안녕
67 | 今日は
68 | `[1:], `
69 | Hello 안녕
70 | Γειά σου 今日は
71 | `[1:]},
72 | }
73 |
74 | func TestWriter(t *testing.T) {
75 | for _, test := range tests {
76 | b := new(bytes.Buffer)
77 | w := NewWriter(b, test.wid, test.flag)
78 | if _, err := w.Write([]byte(test.src)); err != nil {
79 | t.Error(err)
80 | }
81 | if err := w.Flush(); err != nil {
82 | t.Error(err)
83 | }
84 | if g := b.String(); test.want != g {
85 | t.Log("\n" + test.want)
86 | t.Log("\n" + g)
87 | t.Errorf("%q != %q", test.want, g)
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/cmd/agg/num.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "math/big"
5 | "strconv"
6 | )
7 |
8 | func min(s, arg string) agg { return newBinop(s, opmin) }
9 | func max(s, arg string) agg { return newBinop(s, opmax) }
10 | func sum(s, arg string) agg { return newBinop(s, opsum) }
11 |
12 | type binop struct {
13 | v *big.Float
14 | f func(a, b *big.Float) *big.Float
15 | }
16 |
17 | func newBinop(s string, f func(a, b *big.Float) *big.Float) *binop {
18 | v, _ := parseFloat(s)
19 | return &binop{v, f}
20 | }
21 |
22 | func (o *binop) String() string {
23 | if o.v == nil {
24 | return "NaN"
25 | }
26 | return o.v.Text('f', -1)
27 | }
28 |
29 | func (o *binop) merge(s string) {
30 | v, ok := parseFloat(s)
31 | if !ok {
32 | return
33 | }
34 | o.v = o.f(o.v, v)
35 | }
36 |
37 | func opmin(a, b *big.Float) *big.Float {
38 | if a != nil && (b == nil || a.Cmp(b) <= 0) {
39 | return a
40 | }
41 | return b
42 | }
43 |
44 | func opmax(a, b *big.Float) *big.Float {
45 | if a != nil && (b == nil || a.Cmp(b) >= 0) {
46 | return a
47 | }
48 | return b
49 | }
50 |
51 | func opsum(a, b *big.Float) *big.Float {
52 | if a == nil {
53 | return b
54 | } else if b == nil {
55 | return a
56 | }
57 | return a.Add(a, b)
58 | }
59 |
60 | type meanagg struct {
61 | v *big.Float
62 | d float64 // actually an integer
63 | }
64 |
65 | func mean(s, arg string) agg {
66 | v, ok := parseFloat(s)
67 | if !ok {
68 | return &meanagg{new(big.Float), 0}
69 | }
70 | return &meanagg{v, 1}
71 | }
72 |
73 | func (m *meanagg) String() string {
74 | if m.d == 0 {
75 | return "NaN"
76 | }
77 | v := new(big.Float).Quo(m.v, big.NewFloat(m.d))
78 | return v.Text('f', -1)
79 | }
80 |
81 | func (m *meanagg) merge(s string) {
82 | v, ok := parseFloat(s)
83 | if !ok {
84 | return
85 | }
86 | m.v.Add(m.v, v)
87 | m.d++
88 | }
89 |
90 | func parseFloat(s string) (*big.Float, bool) {
91 | v, _, err := big.ParseFloat(s, 0, 1000, big.ToNearestEven)
92 | return v, err == nil
93 | }
94 |
95 | type counter int
96 |
97 | func count(init, arg string) agg { return new(counter) }
98 | func (c *counter) String() string { return strconv.Itoa(int(*c) + 1) }
99 | func (c *counter) merge(string) { *c++ }
100 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/cmd/agg/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | // TODO(kr): tests
4 |
5 | import (
6 | "bufio"
7 | "fmt"
8 | "log"
9 | "math/rand"
10 | "os"
11 | "strings"
12 | "time"
13 | )
14 |
15 | type agg interface {
16 | merge(string)
17 | String() string
18 | }
19 |
20 | var (
21 | key = 0
22 | funcmap = make(map[int]func(init, arg string) agg)
23 | argmap = make(map[int]string)
24 | symtab = map[string]func(init, arg string) agg{
25 | "first": first,
26 | "last": last,
27 | "prefix": prefix,
28 | "sample": sample,
29 | "join": join,
30 | "smin": smin,
31 | "smax": smax,
32 | "min": min,
33 | "max": max,
34 | "sum": sum,
35 | "mean": mean,
36 | "count": count,
37 | "const": constf,
38 | "drop": nil,
39 | }
40 | )
41 |
42 | func main() {
43 | log.SetPrefix("agg: ")
44 | log.SetFlags(0)
45 | rand.Seed(time.Now().UnixNano())
46 | for i, sym := range os.Args[1:] {
47 | if p := strings.IndexByte(sym, ':'); p >= 0 {
48 | sym, argmap[i] = sym[:p], sym[p+1:]
49 | }
50 | if sym == "key" {
51 | key, sym = i, "first"
52 | }
53 | f, ok := symtab[sym]
54 | if !ok {
55 | log.Fatalf("bad function: %q", sym)
56 | }
57 | funcmap[i] = f
58 | }
59 |
60 | sc := bufio.NewScanner(os.Stdin)
61 | var g *group
62 | for sc.Scan() {
63 | ss := strings.Fields(sc.Text())
64 | if !matches(g, ss) {
65 | emit(g)
66 | g = &group{key: ss[key]}
67 | }
68 | mergeLine(g, ss)
69 | }
70 | emit(g)
71 | }
72 |
73 | type group struct {
74 | key string
75 | agg []agg
76 | }
77 |
78 | func matches(g *group, ss []string) bool {
79 | return g != nil && g.key == ss[key]
80 | }
81 |
82 | func emit(g *group) {
83 | if g == nil {
84 | return
85 | }
86 | rest := false
87 | for i, a := range g.agg {
88 | if f, ok := funcmap[i]; ok && f == nil {
89 | continue
90 | }
91 | if rest {
92 | fmt.Print("\t")
93 | }
94 | rest = true
95 | fmt.Print(a)
96 | }
97 | fmt.Println()
98 | }
99 |
100 | func mergeLine(g *group, ss []string) {
101 | for i, s := range ss {
102 | if i >= len(g.agg) {
103 | f := funcmap[i]
104 | if f == nil {
105 | f = first
106 | }
107 | g.agg = append(g.agg, f(s, argmap[i]))
108 | } else {
109 | g.agg[i].merge(s)
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/wrap.go:
--------------------------------------------------------------------------------
1 | package text
2 |
3 | import (
4 | "bytes"
5 | "math"
6 | )
7 |
8 | var (
9 | nl = []byte{'\n'}
10 | sp = []byte{' '}
11 | )
12 |
13 | const defaultPenalty = 1e5
14 |
15 | // Wrap wraps s into a paragraph of lines of length lim, with minimal
16 | // raggedness.
17 | func Wrap(s string, lim int) string {
18 | return string(WrapBytes([]byte(s), lim))
19 | }
20 |
21 | // WrapBytes wraps b into a paragraph of lines of length lim, with minimal
22 | // raggedness.
23 | func WrapBytes(b []byte, lim int) []byte {
24 | words := bytes.Split(bytes.Replace(bytes.TrimSpace(b), nl, sp, -1), sp)
25 | var lines [][]byte
26 | for _, line := range WrapWords(words, 1, lim, defaultPenalty) {
27 | lines = append(lines, bytes.Join(line, sp))
28 | }
29 | return bytes.Join(lines, nl)
30 | }
31 |
32 | // WrapWords is the low-level line-breaking algorithm, useful if you need more
33 | // control over the details of the text wrapping process. For most uses, either
34 | // Wrap or WrapBytes will be sufficient and more convenient.
35 | //
36 | // WrapWords splits a list of words into lines with minimal "raggedness",
37 | // treating each byte as one unit, accounting for spc units between adjacent
38 | // words on each line, and attempting to limit lines to lim units. Raggedness
39 | // is the total error over all lines, where error is the square of the
40 | // difference of the length of the line and lim. Too-long lines (which only
41 | // happen when a single word is longer than lim units) have pen penalty units
42 | // added to the error.
43 | func WrapWords(words [][]byte, spc, lim, pen int) [][][]byte {
44 | n := len(words)
45 |
46 | length := make([][]int, n)
47 | for i := 0; i < n; i++ {
48 | length[i] = make([]int, n)
49 | length[i][i] = len(words[i])
50 | for j := i + 1; j < n; j++ {
51 | length[i][j] = length[i][j-1] + spc + len(words[j])
52 | }
53 | }
54 |
55 | nbrk := make([]int, n)
56 | cost := make([]int, n)
57 | for i := range cost {
58 | cost[i] = math.MaxInt32
59 | }
60 | for i := n - 1; i >= 0; i-- {
61 | if length[i][n-1] <= lim || i == n-1 {
62 | cost[i] = 0
63 | nbrk[i] = n
64 | } else {
65 | for j := i + 1; j < n; j++ {
66 | d := lim - length[i][j-1]
67 | c := d*d + cost[j]
68 | if length[i][j-1] > lim {
69 | c += pen // too-long lines get a worse penalty
70 | }
71 | if c < cost[i] {
72 | cost[i] = c
73 | nbrk[i] = j
74 | }
75 | }
76 | }
77 | }
78 |
79 | var lines [][][]byte
80 | i := 0
81 | for i < n {
82 | lines = append(lines, words[i:nbrk[i]])
83 | i = nbrk[i]
84 | }
85 | return lines
86 | }
87 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/indent_test.go:
--------------------------------------------------------------------------------
1 | package text
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 | )
7 |
8 | type T struct {
9 | inp, exp, pre string
10 | }
11 |
12 | var tests = []T{
13 | {
14 | "The quick brown fox\njumps over the lazy\ndog.\nBut not quickly.\n",
15 | "xxxThe quick brown fox\nxxxjumps over the lazy\nxxxdog.\nxxxBut not quickly.\n",
16 | "xxx",
17 | },
18 | {
19 | "The quick brown fox\njumps over the lazy\ndog.\n\nBut not quickly.",
20 | "xxxThe quick brown fox\nxxxjumps over the lazy\nxxxdog.\n\nxxxBut not quickly.",
21 | "xxx",
22 | },
23 | }
24 |
25 | func TestIndent(t *testing.T) {
26 | for _, test := range tests {
27 | got := Indent(test.inp, test.pre)
28 | if got != test.exp {
29 | t.Errorf("mismatch %q != %q", got, test.exp)
30 | }
31 | }
32 | }
33 |
34 | type IndentWriterTest struct {
35 | inp, exp string
36 | pre []string
37 | }
38 |
39 | var ts = []IndentWriterTest{
40 | {
41 | `
42 | The quick brown fox
43 | jumps over the lazy
44 | dog.
45 | But not quickly.
46 | `[1:],
47 | `
48 | xxxThe quick brown fox
49 | xxxjumps over the lazy
50 | xxxdog.
51 | xxxBut not quickly.
52 | `[1:],
53 | []string{"xxx"},
54 | },
55 | {
56 | `
57 | The quick brown fox
58 | jumps over the lazy
59 | dog.
60 | But not quickly.
61 | `[1:],
62 | `
63 | xxaThe quick brown fox
64 | xxxjumps over the lazy
65 | xxxdog.
66 | xxxBut not quickly.
67 | `[1:],
68 | []string{"xxa", "xxx"},
69 | },
70 | {
71 | `
72 | The quick brown fox
73 | jumps over the lazy
74 | dog.
75 | But not quickly.
76 | `[1:],
77 | `
78 | xxaThe quick brown fox
79 | xxbjumps over the lazy
80 | xxcdog.
81 | xxxBut not quickly.
82 | `[1:],
83 | []string{"xxa", "xxb", "xxc", "xxx"},
84 | },
85 | {
86 | `
87 | The quick brown fox
88 | jumps over the lazy
89 | dog.
90 |
91 | But not quickly.`[1:],
92 | `
93 | xxaThe quick brown fox
94 | xxxjumps over the lazy
95 | xxxdog.
96 | xxx
97 | xxxBut not quickly.`[1:],
98 | []string{"xxa", "xxx"},
99 | },
100 | }
101 |
102 | func TestIndentWriter(t *testing.T) {
103 | for _, test := range ts {
104 | b := new(bytes.Buffer)
105 | pre := make([][]byte, len(test.pre))
106 | for i := range test.pre {
107 | pre[i] = []byte(test.pre[i])
108 | }
109 | w := NewIndentWriter(b, pre...)
110 | if _, err := w.Write([]byte(test.inp)); err != nil {
111 | t.Error(err)
112 | }
113 | if got := b.String(); got != test.exp {
114 | t.Errorf("mismatch %q != %q", got, test.exp)
115 | t.Log(got)
116 | t.Log(test.exp)
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/cmd/agg/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Agg computes aggregate values over tabular text.
4 | It behaves somewhat like the SQL “GROUP BY” clause.
5 |
6 | Usage:
7 |
8 | agg [function...]
9 |
10 | It reads input from stdin as a sequence of records, one per line.
11 | It treats each line as a set of fields separated by white space.
12 | One field (the first, by default) is designated as the key.
13 | Successive lines with equal keys are grouped into a group,
14 | and agg produces one line of output for each group.
15 | (Note that only contiguous input lines can form a group.
16 | If you need to make sure that all records for a given key
17 | are grouped together, sort the input first.)
18 |
19 | For each remaining field,
20 | agg applies a function to all the values in the group,
21 | producing a single output value.
22 | The command line arguments specify which functions to use,
23 | one per field in the input table.
24 |
25 | Functions
26 |
27 | The available functions are:
28 |
29 | key group by this field (default for field 1)
30 | first value from first line of group (default for rest)
31 | last value from last line of group
32 | sample value from any line of group, uniformly at random
33 | prefix longest common string prefix
34 | join:sep concatenate strings with given sep
35 | smin lexically least string
36 | smax lexically greatest string
37 | min numerically least value
38 | max numerically greatest value
39 | sum numeric sum
40 | mean arithmetic mean
41 | count number of records (ignores input value)
42 | const:val print val, ignoring input
43 | drop omit the column entirely
44 |
45 | The numeric functions skip items that don't parse as numbers.
46 |
47 | Examples
48 |
49 | Using the following input:
50 |
51 | $ cat >input
52 | -rwx alice 100 /home/alice/bin/crdt
53 | -rw- alice 210002 /home/alice/thesis.tex
54 | -rw- bob 10051 /home/bob/expenses.tab
55 | -rwx kr 862060 /home/kr/bin/blog
56 | -rwx kr 304608 /home/kr/bin/agg
57 |
58 | Disk usage for each user, plus where that disk usage occurs
59 | (longest common prefix of filesystem paths):
60 |
61 | $ agg ?@[]^_{|}~"` // https://golang.org/issue/3546
45 | }
46 |
47 | type dashTag struct {
48 | V string `json:"-,"`
49 | }
50 |
51 | type emptyTag struct {
52 | W string
53 | }
54 |
55 | type misnamedTag struct {
56 | X string `jsom:"Misnamed"`
57 | }
58 |
59 | type badFormatTag struct {
60 | Y string `:"BadFormat"`
61 | }
62 |
63 | type badCodeTag struct {
64 | Z string `json:" !\"#&'()*+,."`
65 | }
66 |
67 | type spaceTag struct {
68 | Q string `json:"With space"`
69 | }
70 |
71 | type unicodeTag struct {
72 | W string `json:"Ελλάδα"`
73 | }
74 |
75 | var structTagObjectKeyTests = []struct {
76 | raw interface{}
77 | value string
78 | key string
79 | }{
80 | {basicLatin2xTag{"2x"}, "2x", "$%-/"},
81 | {basicLatin3xTag{"3x"}, "3x", "0123456789"},
82 | {basicLatin4xTag{"4x"}, "4x", "ABCDEFGHIJKLMO"},
83 | {basicLatin5xTag{"5x"}, "5x", "PQRSTUVWXYZ_"},
84 | {basicLatin6xTag{"6x"}, "6x", "abcdefghijklmno"},
85 | {basicLatin7xTag{"7x"}, "7x", "pqrstuvwxyz"},
86 | {miscPlaneTag{"いろはにほへと"}, "いろはにほへと", "色は匂へど"},
87 | {dashTag{"foo"}, "foo", "-"},
88 | {emptyTag{"Pour Moi"}, "Pour Moi", "W"},
89 | {misnamedTag{"Animal Kingdom"}, "Animal Kingdom", "X"},
90 | {badFormatTag{"Orfevre"}, "Orfevre", "Y"},
91 | {badCodeTag{"Reliable Man"}, "Reliable Man", "Z"},
92 | {percentSlashTag{"brut"}, "brut", "text/html%"},
93 | {punctuationTag{"Union Rags"}, "Union Rags", "!#$%&()*+-./:<=>?@[]^_{|}~"},
94 | {spaceTag{"Perreddu"}, "Perreddu", "With space"},
95 | {unicodeTag{"Loukanikos"}, "Loukanikos", "Ελλάδα"},
96 | }
97 |
98 | func TestStructTagObjectKey(t *testing.T) {
99 | for _, tt := range structTagObjectKeyTests {
100 | b, err := Marshal(tt.raw)
101 | if err != nil {
102 | t.Fatalf("Marshal(%#q) failed: %v", tt.raw, err)
103 | }
104 | var f interface{}
105 | err = Unmarshal(b, &f)
106 | if err != nil {
107 | t.Fatalf("Unmarshal(%#q) failed: %v", b, err)
108 | }
109 | for i, v := range f.(map[string]interface{}) {
110 | switch i {
111 | case tt.key:
112 | if s, ok := v.(string); !ok || s != tt.value {
113 | t.Fatalf("Unexpected value: %#q, want %v", s, tt.value)
114 | }
115 | default:
116 | t.Fatalf("Unexpected key: %#q, from %#q", i, b)
117 | }
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/fold_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package json
6 |
7 | import (
8 | "bytes"
9 | "strings"
10 | "testing"
11 | "unicode/utf8"
12 | )
13 |
14 | var foldTests = []struct {
15 | fn func(s, t []byte) bool
16 | s, t string
17 | want bool
18 | }{
19 | {equalFoldRight, "", "", true},
20 | {equalFoldRight, "a", "a", true},
21 | {equalFoldRight, "", "a", false},
22 | {equalFoldRight, "a", "", false},
23 | {equalFoldRight, "a", "A", true},
24 | {equalFoldRight, "AB", "ab", true},
25 | {equalFoldRight, "AB", "ac", false},
26 | {equalFoldRight, "sbkKc", "ſbKKc", true},
27 | {equalFoldRight, "SbKkc", "ſbKKc", true},
28 | {equalFoldRight, "SbKkc", "ſbKK", false},
29 | {equalFoldRight, "e", "é", false},
30 | {equalFoldRight, "s", "S", true},
31 |
32 | {simpleLetterEqualFold, "", "", true},
33 | {simpleLetterEqualFold, "abc", "abc", true},
34 | {simpleLetterEqualFold, "abc", "ABC", true},
35 | {simpleLetterEqualFold, "abc", "ABCD", false},
36 | {simpleLetterEqualFold, "abc", "xxx", false},
37 |
38 | {asciiEqualFold, "a_B", "A_b", true},
39 | {asciiEqualFold, "aa@", "aa`", false}, // verify 0x40 and 0x60 aren't case-equivalent
40 | }
41 |
42 | func TestFold(t *testing.T) {
43 | for i, tt := range foldTests {
44 | if got := tt.fn([]byte(tt.s), []byte(tt.t)); got != tt.want {
45 | t.Errorf("%d. %q, %q = %v; want %v", i, tt.s, tt.t, got, tt.want)
46 | }
47 | truth := strings.EqualFold(tt.s, tt.t)
48 | if truth != tt.want {
49 | t.Errorf("strings.EqualFold doesn't agree with case %d", i)
50 | }
51 | }
52 | }
53 |
54 | func TestFoldAgainstUnicode(t *testing.T) {
55 | const bufSize = 5
56 | buf1 := make([]byte, 0, bufSize)
57 | buf2 := make([]byte, 0, bufSize)
58 | var runes []rune
59 | for i := 0x20; i <= 0x7f; i++ {
60 | runes = append(runes, rune(i))
61 | }
62 | runes = append(runes, kelvin, smallLongEss)
63 |
64 | funcs := []struct {
65 | name string
66 | fold func(s, t []byte) bool
67 | letter bool // must be ASCII letter
68 | simple bool // must be simple ASCII letter (not 'S' or 'K')
69 | }{
70 | {
71 | name: "equalFoldRight",
72 | fold: equalFoldRight,
73 | },
74 | {
75 | name: "asciiEqualFold",
76 | fold: asciiEqualFold,
77 | simple: true,
78 | },
79 | {
80 | name: "simpleLetterEqualFold",
81 | fold: simpleLetterEqualFold,
82 | simple: true,
83 | letter: true,
84 | },
85 | }
86 |
87 | for _, ff := range funcs {
88 | for _, r := range runes {
89 | if r >= utf8.RuneSelf {
90 | continue
91 | }
92 | if ff.letter && !isASCIILetter(byte(r)) {
93 | continue
94 | }
95 | if ff.simple && (r == 's' || r == 'S' || r == 'k' || r == 'K') {
96 | continue
97 | }
98 | for _, r2 := range runes {
99 | buf1 := append(buf1[:0], 'x')
100 | buf2 := append(buf2[:0], 'x')
101 | buf1 = buf1[:1+utf8.EncodeRune(buf1[1:bufSize], r)]
102 | buf2 = buf2[:1+utf8.EncodeRune(buf2[1:bufSize], r2)]
103 | buf1 = append(buf1, 'x')
104 | buf2 = append(buf2, 'x')
105 | want := bytes.EqualFold(buf1, buf2)
106 | if got := ff.fold(buf1, buf2); got != want {
107 | t.Errorf("%s(%q, %q) = %v; want %v", ff.name, buf1, buf2, got, want)
108 | }
109 | }
110 | }
111 | }
112 | }
113 |
114 | func isASCIILetter(b byte) bool {
115 | return ('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z')
116 | }
117 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/pretty/pretty.go:
--------------------------------------------------------------------------------
1 | // Package pretty provides pretty-printing for Go values. This is
2 | // useful during debugging, to avoid wrapping long output lines in
3 | // the terminal.
4 | //
5 | // It provides a function, Formatter, that can be used with any
6 | // function that accepts a format string. It also provides
7 | // convenience wrappers for functions in packages fmt and log.
8 | package pretty
9 |
10 | import (
11 | "fmt"
12 | "io"
13 | "log"
14 | "reflect"
15 | )
16 |
17 | // Errorf is a convenience wrapper for fmt.Errorf.
18 | //
19 | // Calling Errorf(f, x, y) is equivalent to
20 | // fmt.Errorf(f, Formatter(x), Formatter(y)).
21 | func Errorf(format string, a ...interface{}) error {
22 | return fmt.Errorf(format, wrap(a, false)...)
23 | }
24 |
25 | // Fprintf is a convenience wrapper for fmt.Fprintf.
26 | //
27 | // Calling Fprintf(w, f, x, y) is equivalent to
28 | // fmt.Fprintf(w, f, Formatter(x), Formatter(y)).
29 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error error) {
30 | return fmt.Fprintf(w, format, wrap(a, false)...)
31 | }
32 |
33 | // Log is a convenience wrapper for log.Printf.
34 | //
35 | // Calling Log(x, y) is equivalent to
36 | // log.Print(Formatter(x), Formatter(y)), but each operand is
37 | // formatted with "%# v".
38 | func Log(a ...interface{}) {
39 | log.Print(wrap(a, true)...)
40 | }
41 |
42 | // Logf is a convenience wrapper for log.Printf.
43 | //
44 | // Calling Logf(f, x, y) is equivalent to
45 | // log.Printf(f, Formatter(x), Formatter(y)).
46 | func Logf(format string, a ...interface{}) {
47 | log.Printf(format, wrap(a, false)...)
48 | }
49 |
50 | // Logln is a convenience wrapper for log.Printf.
51 | //
52 | // Calling Logln(x, y) is equivalent to
53 | // log.Println(Formatter(x), Formatter(y)), but each operand is
54 | // formatted with "%# v".
55 | func Logln(a ...interface{}) {
56 | log.Println(wrap(a, true)...)
57 | }
58 |
59 | // Print pretty-prints its operands and writes to standard output.
60 | //
61 | // Calling Print(x, y) is equivalent to
62 | // fmt.Print(Formatter(x), Formatter(y)), but each operand is
63 | // formatted with "%# v".
64 | func Print(a ...interface{}) (n int, errno error) {
65 | return fmt.Print(wrap(a, true)...)
66 | }
67 |
68 | // Printf is a convenience wrapper for fmt.Printf.
69 | //
70 | // Calling Printf(f, x, y) is equivalent to
71 | // fmt.Printf(f, Formatter(x), Formatter(y)).
72 | func Printf(format string, a ...interface{}) (n int, errno error) {
73 | return fmt.Printf(format, wrap(a, false)...)
74 | }
75 |
76 | // Println pretty-prints its operands and writes to standard output.
77 | //
78 | // Calling Print(x, y) is equivalent to
79 | // fmt.Println(Formatter(x), Formatter(y)), but each operand is
80 | // formatted with "%# v".
81 | func Println(a ...interface{}) (n int, errno error) {
82 | return fmt.Println(wrap(a, true)...)
83 | }
84 |
85 | // Sprint is a convenience wrapper for fmt.Sprintf.
86 | //
87 | // Calling Sprint(x, y) is equivalent to
88 | // fmt.Sprint(Formatter(x), Formatter(y)), but each operand is
89 | // formatted with "%# v".
90 | func Sprint(a ...interface{}) string {
91 | return fmt.Sprint(wrap(a, true)...)
92 | }
93 |
94 | // Sprintf is a convenience wrapper for fmt.Sprintf.
95 | //
96 | // Calling Sprintf(f, x, y) is equivalent to
97 | // fmt.Sprintf(f, Formatter(x), Formatter(y)).
98 | func Sprintf(format string, a ...interface{}) string {
99 | return fmt.Sprintf(format, wrap(a, false)...)
100 | }
101 |
102 | func wrap(a []interface{}, force bool) []interface{} {
103 | w := make([]interface{}, len(a))
104 | for i, x := range a {
105 | w[i] = formatter{v: reflect.ValueOf(x), force: force}
106 | }
107 | return w
108 | }
109 |
--------------------------------------------------------------------------------
/vendor/github.com/golang/glog/glog_file.go:
--------------------------------------------------------------------------------
1 | // Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
2 | //
3 | // Copyright 2013 Google Inc. All Rights Reserved.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 |
17 | // File I/O for logs.
18 |
19 | package glog
20 |
21 | import (
22 | "errors"
23 | "flag"
24 | "fmt"
25 | "os"
26 | "os/user"
27 | "path/filepath"
28 | "strings"
29 | "sync"
30 | "time"
31 | )
32 |
33 | // MaxSize is the maximum size of a log file in bytes.
34 | var MaxSize uint64 = 1024 * 1024 * 1800
35 |
36 | // logDirs lists the candidate directories for new log files.
37 | var logDirs []string
38 |
39 | // If non-empty, overrides the choice of directory in which to write logs.
40 | // See createLogDirs for the full list of possible destinations.
41 | var logDir = flag.String("log_dir", "", "If non-empty, write log files in this directory")
42 |
43 | func createLogDirs() {
44 | if *logDir != "" {
45 | logDirs = append(logDirs, *logDir)
46 | }
47 | logDirs = append(logDirs, os.TempDir())
48 | }
49 |
50 | var (
51 | pid = os.Getpid()
52 | program = filepath.Base(os.Args[0])
53 | host = "unknownhost"
54 | userName = "unknownuser"
55 | )
56 |
57 | func init() {
58 | h, err := os.Hostname()
59 | if err == nil {
60 | host = shortHostname(h)
61 | }
62 |
63 | current, err := user.Current()
64 | if err == nil {
65 | userName = current.Username
66 | }
67 |
68 | // Sanitize userName since it may contain filepath separators on Windows.
69 | userName = strings.Replace(userName, `\`, "_", -1)
70 | }
71 |
72 | // shortHostname returns its argument, truncating at the first period.
73 | // For instance, given "www.google.com" it returns "www".
74 | func shortHostname(hostname string) string {
75 | if i := strings.Index(hostname, "."); i >= 0 {
76 | return hostname[:i]
77 | }
78 | return hostname
79 | }
80 |
81 | // logName returns a new log file name containing tag, with start time t, and
82 | // the name for the symlink for tag.
83 | func logName(tag string, t time.Time) (name, link string) {
84 | name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d",
85 | program,
86 | host,
87 | userName,
88 | tag,
89 | t.Year(),
90 | t.Month(),
91 | t.Day(),
92 | t.Hour(),
93 | t.Minute(),
94 | t.Second(),
95 | pid)
96 | return name, program + "." + tag
97 | }
98 |
99 | var onceLogDirs sync.Once
100 |
101 | // create creates a new log file and returns the file and its filename, which
102 | // contains tag ("INFO", "FATAL", etc.) and t. If the file is created
103 | // successfully, create also attempts to update the symlink for that tag, ignoring
104 | // errors.
105 | func create(tag string, t time.Time) (f *os.File, filename string, err error) {
106 | onceLogDirs.Do(createLogDirs)
107 | if len(logDirs) == 0 {
108 | return nil, "", errors.New("log: no log dirs")
109 | }
110 | name, link := logName(tag, t)
111 | var lastErr error
112 | for _, dir := range logDirs {
113 | fname := filepath.Join(dir, name)
114 | f, err := os.Create(fname)
115 | if err == nil {
116 | symlink := filepath.Join(dir, link)
117 | os.Remove(symlink) // ignore err
118 | os.Symlink(name, symlink) // ignore err
119 | return f, fname, nil
120 | }
121 | lastErr = err
122 | }
123 | return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr)
124 | }
125 |
--------------------------------------------------------------------------------
/vendor/github.com/kr/text/colwriter/column.go:
--------------------------------------------------------------------------------
1 | // Package colwriter provides a write filter that formats
2 | // input lines in multiple columns.
3 | //
4 | // The package is a straightforward translation from
5 | // /src/cmd/draw/mc.c in Plan 9 from User Space.
6 | package colwriter
7 |
8 | import (
9 | "bytes"
10 | "io"
11 | "unicode/utf8"
12 | )
13 |
14 | const (
15 | tab = 4
16 | )
17 |
18 | const (
19 | // Print each input line ending in a colon ':' separately.
20 | BreakOnColon uint = 1 << iota
21 | )
22 |
23 | // A Writer is a filter that arranges input lines in as many columns as will
24 | // fit in its width. Tab '\t' chars in the input are translated to sequences
25 | // of spaces ending at multiples of 4 positions.
26 | //
27 | // If BreakOnColon is set, each input line ending in a colon ':' is written
28 | // separately.
29 | //
30 | // The Writer assumes that all Unicode code points have the same width; this
31 | // may not be true in some fonts.
32 | type Writer struct {
33 | w io.Writer
34 | buf []byte
35 | width int
36 | flag uint
37 | }
38 |
39 | // NewWriter allocates and initializes a new Writer writing to w.
40 | // Parameter width controls the total number of characters on each line
41 | // across all columns.
42 | func NewWriter(w io.Writer, width int, flag uint) *Writer {
43 | return &Writer{
44 | w: w,
45 | width: width,
46 | flag: flag,
47 | }
48 | }
49 |
50 | // Write writes p to the writer w. The only errors returned are ones
51 | // encountered while writing to the underlying output stream.
52 | func (w *Writer) Write(p []byte) (n int, err error) {
53 | var linelen int
54 | var lastWasColon bool
55 | for i, c := range p {
56 | w.buf = append(w.buf, c)
57 | linelen++
58 | if c == '\t' {
59 | w.buf[len(w.buf)-1] = ' '
60 | for linelen%tab != 0 {
61 | w.buf = append(w.buf, ' ')
62 | linelen++
63 | }
64 | }
65 | if w.flag&BreakOnColon != 0 && c == ':' {
66 | lastWasColon = true
67 | } else if lastWasColon {
68 | if c == '\n' {
69 | pos := bytes.LastIndex(w.buf[:len(w.buf)-1], []byte{'\n'})
70 | if pos < 0 {
71 | pos = 0
72 | }
73 | line := w.buf[pos:]
74 | w.buf = w.buf[:pos]
75 | if err = w.columnate(); err != nil {
76 | if len(line) < i {
77 | return i - len(line), err
78 | }
79 | return 0, err
80 | }
81 | if n, err := w.w.Write(line); err != nil {
82 | if r := len(line) - n; r < i {
83 | return i - r, err
84 | }
85 | return 0, err
86 | }
87 | }
88 | lastWasColon = false
89 | }
90 | if c == '\n' {
91 | linelen = 0
92 | }
93 | }
94 | return len(p), nil
95 | }
96 |
97 | // Flush should be called after the last call to Write to ensure that any data
98 | // buffered in the Writer is written to output.
99 | func (w *Writer) Flush() error {
100 | return w.columnate()
101 | }
102 |
103 | func (w *Writer) columnate() error {
104 | words := bytes.Split(w.buf, []byte{'\n'})
105 | w.buf = nil
106 | if len(words[len(words)-1]) == 0 {
107 | words = words[:len(words)-1]
108 | }
109 | maxwidth := 0
110 | for _, wd := range words {
111 | if n := utf8.RuneCount(wd); n > maxwidth {
112 | maxwidth = n
113 | }
114 | }
115 | maxwidth++ // space char
116 | wordsPerLine := w.width / maxwidth
117 | if wordsPerLine <= 0 {
118 | wordsPerLine = 1
119 | }
120 | nlines := (len(words) + wordsPerLine - 1) / wordsPerLine
121 | for i := 0; i < nlines; i++ {
122 | col := 0
123 | endcol := 0
124 | for j := i; j < len(words); j += nlines {
125 | endcol += maxwidth
126 | _, err := w.w.Write(words[j])
127 | if err != nil {
128 | return err
129 | }
130 | col += utf8.RuneCount(words[j])
131 | if j+nlines < len(words) {
132 | for col < endcol {
133 | _, err := w.w.Write([]byte{' '})
134 | if err != nil {
135 | return err
136 | }
137 | col++
138 | }
139 | }
140 | }
141 | _, err := w.w.Write([]byte{'\n'})
142 | if err != nil {
143 | return err
144 | }
145 | }
146 | return nil
147 | }
148 |
--------------------------------------------------------------------------------
/indent.go:
--------------------------------------------------------------------------------
1 | // Copyright 2010 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package json
6 |
7 | import "bytes"
8 |
9 | // Compact appends to dst the JSON-encoded src with
10 | // insignificant space characters elided.
11 | func Compact(dst *bytes.Buffer, src []byte) error {
12 | return compact(dst, src, false)
13 | }
14 |
15 | func compact(dst *bytes.Buffer, src []byte, escape bool) error {
16 | origLen := dst.Len()
17 | var scan scanner
18 | scan.reset()
19 | start := 0
20 | for i, c := range src {
21 | if escape && (c == '<' || c == '>' || c == '&') {
22 | if start < i {
23 | dst.Write(src[start:i])
24 | }
25 | dst.WriteString(`\u00`)
26 | dst.WriteByte(hex[c>>4])
27 | dst.WriteByte(hex[c&0xF])
28 | start = i + 1
29 | }
30 | // Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
31 | if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
32 | if start < i {
33 | dst.Write(src[start:i])
34 | }
35 | dst.WriteString(`\u202`)
36 | dst.WriteByte(hex[src[i+2]&0xF])
37 | start = i + 3
38 | }
39 | v := scan.step(&scan, c)
40 | if v >= scanSkipSpace {
41 | if v == scanError {
42 | break
43 | }
44 | if start < i {
45 | dst.Write(src[start:i])
46 | }
47 | start = i + 1
48 | }
49 | }
50 | if scan.eof() == scanError {
51 | dst.Truncate(origLen)
52 | return scan.err
53 | }
54 | if start < len(src) {
55 | dst.Write(src[start:])
56 | }
57 | return nil
58 | }
59 |
60 | func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
61 | dst.WriteByte('\n')
62 | dst.WriteString(prefix)
63 | for i := 0; i < depth; i++ {
64 | dst.WriteString(indent)
65 | }
66 | }
67 |
68 | // Indent appends to dst an indented form of the JSON-encoded src.
69 | // Each element in a JSON object or array begins on a new,
70 | // indented line beginning with prefix followed by one or more
71 | // copies of indent according to the indentation nesting.
72 | // The data appended to dst does not begin with the prefix nor
73 | // any indentation, to make it easier to embed inside other formatted JSON data.
74 | // Although leading space characters (space, tab, carriage return, newline)
75 | // at the beginning of src are dropped, trailing space characters
76 | // at the end of src are preserved and copied to dst.
77 | // For example, if src has no trailing spaces, neither will dst;
78 | // if src ends in a trailing newline, so will dst.
79 | func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
80 | origLen := dst.Len()
81 | var scan scanner
82 | scan.reset()
83 | needIndent := false
84 | depth := 0
85 | for _, c := range src {
86 | scan.bytes++
87 | v := scan.step(&scan, c)
88 | if v == scanSkipSpace {
89 | continue
90 | }
91 | if v == scanError {
92 | break
93 | }
94 | if needIndent && v != scanEndObject && v != scanEndArray {
95 | needIndent = false
96 | depth++
97 | newline(dst, prefix, indent, depth)
98 | }
99 |
100 | // Emit semantically uninteresting bytes
101 | // (in particular, punctuation in strings) unmodified.
102 | if v == scanContinue {
103 | dst.WriteByte(c)
104 | continue
105 | }
106 |
107 | // Add spacing around real punctuation.
108 | switch c {
109 | case '{', '[':
110 | // delay indent so that empty object and array are formatted as {} and [].
111 | needIndent = true
112 | dst.WriteByte(c)
113 |
114 | case ',':
115 | dst.WriteByte(c)
116 | newline(dst, prefix, indent, depth)
117 |
118 | case ':':
119 | dst.WriteByte(c)
120 | dst.WriteByte(' ')
121 |
122 | case '}', ']':
123 | if needIndent {
124 | // suppress indent in empty object/array
125 | needIndent = false
126 | } else {
127 | depth--
128 | newline(dst, prefix, indent, depth)
129 | }
130 | dst.WriteByte(c)
131 |
132 | default:
133 | dst.WriteByte(c)
134 | }
135 | }
136 | if scan.eof() == scanError {
137 | dst.Truncate(origLen)
138 | return scan.err
139 | }
140 | return nil
141 | }
142 |
--------------------------------------------------------------------------------
/fold.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package json
6 |
7 | import (
8 | "bytes"
9 | "unicode/utf8"
10 | )
11 |
12 | const (
13 | caseMask = ^byte(0x20) // Mask to ignore case in ASCII.
14 | kelvin = '\u212a'
15 | smallLongEss = '\u017f'
16 | )
17 |
18 | // foldFunc returns one of four different case folding equivalence
19 | // functions, from most general (and slow) to fastest:
20 | //
21 | // 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8
22 | // 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S')
23 | // 3) asciiEqualFold, no special, but includes non-letters (including _)
24 | // 4) simpleLetterEqualFold, no specials, no non-letters.
25 | //
26 | // The letters S and K are special because they map to 3 runes, not just 2:
27 | // * S maps to s and to U+017F 'ſ' Latin small letter long s
28 | // * k maps to K and to U+212A 'K' Kelvin sign
29 | // See https://play.golang.org/p/tTxjOc0OGo
30 | //
31 | // The returned function is specialized for matching against s and
32 | // should only be given s. It's not curried for performance reasons.
33 | func foldFunc(s []byte) func(s, t []byte) bool {
34 | nonLetter := false
35 | special := false // special letter
36 | for _, b := range s {
37 | if b >= utf8.RuneSelf {
38 | return bytes.EqualFold
39 | }
40 | upper := b & caseMask
41 | if upper < 'A' || upper > 'Z' {
42 | nonLetter = true
43 | } else if upper == 'K' || upper == 'S' {
44 | // See above for why these letters are special.
45 | special = true
46 | }
47 | }
48 | if special {
49 | return equalFoldRight
50 | }
51 | if nonLetter {
52 | return asciiEqualFold
53 | }
54 | return simpleLetterEqualFold
55 | }
56 |
57 | // equalFoldRight is a specialization of bytes.EqualFold when s is
58 | // known to be all ASCII (including punctuation), but contains an 's',
59 | // 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t.
60 | // See comments on foldFunc.
61 | func equalFoldRight(s, t []byte) bool {
62 | for _, sb := range s {
63 | if len(t) == 0 {
64 | return false
65 | }
66 | tb := t[0]
67 | if tb < utf8.RuneSelf {
68 | if sb != tb {
69 | sbUpper := sb & caseMask
70 | if 'A' <= sbUpper && sbUpper <= 'Z' {
71 | if sbUpper != tb&caseMask {
72 | return false
73 | }
74 | } else {
75 | return false
76 | }
77 | }
78 | t = t[1:]
79 | continue
80 | }
81 | // sb is ASCII and t is not. t must be either kelvin
82 | // sign or long s; sb must be s, S, k, or K.
83 | tr, size := utf8.DecodeRune(t)
84 | switch sb {
85 | case 's', 'S':
86 | if tr != smallLongEss {
87 | return false
88 | }
89 | case 'k', 'K':
90 | if tr != kelvin {
91 | return false
92 | }
93 | default:
94 | return false
95 | }
96 | t = t[size:]
97 |
98 | }
99 | if len(t) > 0 {
100 | return false
101 | }
102 | return true
103 | }
104 |
105 | // asciiEqualFold is a specialization of bytes.EqualFold for use when
106 | // s is all ASCII (but may contain non-letters) and contains no
107 | // special-folding letters.
108 | // See comments on foldFunc.
109 | func asciiEqualFold(s, t []byte) bool {
110 | if len(s) != len(t) {
111 | return false
112 | }
113 | for i, sb := range s {
114 | tb := t[i]
115 | if sb == tb {
116 | continue
117 | }
118 | if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') {
119 | if sb&caseMask != tb&caseMask {
120 | return false
121 | }
122 | } else {
123 | return false
124 | }
125 | }
126 | return true
127 | }
128 |
129 | // simpleLetterEqualFold is a specialization of bytes.EqualFold for
130 | // use when s is all ASCII letters (no underscores, etc) and also
131 | // doesn't contain 'k', 'K', 's', or 'S'.
132 | // See comments on foldFunc.
133 | func simpleLetterEqualFold(s, t []byte) bool {
134 | if len(s) != len(t) {
135 | return false
136 | }
137 | for i, b := range s {
138 | if b&caseMask != t[i]&caseMask {
139 | return false
140 | }
141 | }
142 | return true
143 | }
144 |
--------------------------------------------------------------------------------
/jsonutil/obj.go:
--------------------------------------------------------------------------------
1 | package jsonutil
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/koki/json"
8 | errutil "github.com/koki/structurederrors"
9 | )
10 |
11 | // GetOnlyMapEntry get the only entry from a map. Error if the map doesn't contain exactly one entry.
12 | func GetOnlyMapEntry(obj map[string]interface{}) (string, interface{}, error) {
13 | if len(obj) != 1 {
14 | return "", nil, errutil.InvalidInstanceErrorf(obj, "expected only one entry")
15 | }
16 |
17 | for key, val := range obj {
18 | return key, val, nil
19 | }
20 |
21 | panic("unreachable")
22 | return "", nil, fmt.Errorf("unreachable")
23 | }
24 |
25 | func GetStringEntry(obj map[string]interface{}, key string) (string, error) {
26 | if val, ok := obj[key]; ok {
27 | if str, ok := val.(string); ok {
28 | return str, nil
29 | }
30 |
31 | return "", errutil.InvalidValueErrorf(obj, "entry for key (%s) is not a string", key)
32 | }
33 |
34 | return "", errutil.InvalidValueErrorf(obj, "no entry for key (%s)", key)
35 | }
36 |
37 | func UnmarshalMap(data map[string]interface{}, target interface{}) error {
38 | b, err := json.Marshal(data)
39 | if err != nil {
40 | // This should be impossible.
41 | panic(err)
42 | }
43 |
44 | // Let the caller of UnmarshalMap fill in the correct error context.
45 | return json.Unmarshal(b, target)
46 | }
47 |
48 | func MarshalMap(source interface{}) (map[string]interface{}, error) {
49 | b, err := json.Marshal(source)
50 | if err != nil {
51 | // Let the caller of MarshalMap fill in the correct error context.
52 | return nil, err
53 | }
54 |
55 | obj := map[string]interface{}{}
56 | err = json.Unmarshal(b, &obj)
57 |
58 | // Let the caller of MarshalMap fill in the correct error context.
59 | return obj, err
60 | }
61 |
62 | type ExtraneousFieldsError struct {
63 | Paths [][]string
64 | }
65 |
66 | func (e *ExtraneousFieldsError) Error() string {
67 | paths := make([]string, len(e.Paths))
68 | for i, path := range e.Paths {
69 | paths[i] = "$." + strings.Join(path, ".")
70 | }
71 | return fmt.Sprintf("extraneous fields (typos?) at paths: %s", strings.Join(paths, ", "))
72 | }
73 |
74 | // ExtraneousFieldPaths finds paths in "data" that aren't in "parsed" by serializing
75 | // "parsed" to a dictionary and recursively comparing its fields to those of "data".
76 | func ExtraneousFieldPaths(data map[string]interface{}, parsed interface{}) ([][]string, error) {
77 | unparsed, err := MarshalMap(parsed)
78 | if err != nil {
79 | return nil, err
80 | }
81 |
82 | return ExtraneousMapPaths([]string{}, data, unparsed), nil
83 | }
84 |
85 | func ExtraneousMapPaths(prefix []string, before map[string]interface{}, after interface{}) [][]string {
86 | paths := [][]string{}
87 | if after, ok := after.(map[string]interface{}); ok {
88 | for key, beforeVal := range before {
89 | // Don't count empty fields as extraneous.
90 | if FieldValIsEmpty(beforeVal) {
91 | continue
92 | }
93 | newPrefix := ExtendPrefix(prefix, key)
94 |
95 | // Is the field also present in "after"?
96 | if afterVal, ok := after[key]; !ok {
97 | // Nope!
98 | paths = append(paths, newPrefix)
99 | } else {
100 | paths = append(paths, ExtraneousAnyPaths(newPrefix, beforeVal, afterVal)...)
101 | }
102 | }
103 | }
104 |
105 | return paths
106 | }
107 |
108 | func ExtraneousSlicePaths(prefix []string, before []interface{}, after interface{}) [][]string {
109 | paths := [][]string{}
110 | if after, ok := after.([]interface{}); ok {
111 | for i, beforeVal := range before {
112 | // Don't count empty fields as extraneous.
113 | if FieldValIsEmpty(beforeVal) {
114 | continue
115 | }
116 | newPrefix := ExtendPrefix(prefix, fmt.Sprintf("%d", i))
117 |
118 | // Is the field also present in "after"
119 | if i >= len(after) {
120 | // Nope!
121 | paths = append(paths, newPrefix)
122 | } else {
123 | afterVal := after[i]
124 | paths = append(paths, ExtraneousAnyPaths(newPrefix, beforeVal, afterVal)...)
125 | }
126 | }
127 | }
128 |
129 | return paths
130 | }
131 |
132 | func ExtendPrefix(prefix []string, segment string) []string {
133 | return append(append([]string{}, prefix...), segment)
134 | }
135 |
136 | func ExtraneousAnyPaths(prefix []string, before interface{}, after interface{}) [][]string {
137 | paths := [][]string{}
138 | if !FieldValIsEmpty(before) {
139 | switch before := before.(type) {
140 | case []interface{}:
141 | paths = append(paths, ExtraneousSlicePaths(prefix, before, after)...)
142 | case map[string]interface{}:
143 | paths = append(paths, ExtraneousMapPaths(prefix, before, after)...)
144 | }
145 | }
146 |
147 | return paths
148 | }
149 |
150 | func FieldValIsEmpty(fieldVal interface{}) bool {
151 | if fieldVal == nil {
152 | return true
153 | }
154 |
155 | switch fieldVal := fieldVal.(type) {
156 | case string:
157 | if len(fieldVal) == 0 {
158 | return true
159 | }
160 | case []interface{}:
161 | if len(fieldVal) == 0 {
162 | return true
163 | }
164 | case float64:
165 | if fieldVal == 0 {
166 | return true
167 | }
168 | case bool:
169 | if !fieldVal {
170 | return true
171 | }
172 | case map[string]interface{}:
173 | if len(fieldVal) == 0 {
174 | return true
175 | }
176 | }
177 | return false
178 | }
179 |
--------------------------------------------------------------------------------
/tables.go:
--------------------------------------------------------------------------------
1 | // Copyright 2016 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package json
6 |
7 | import "unicode/utf8"
8 |
9 | // safeSet holds the value true if the ASCII character with the given array
10 | // position can be represented inside a JSON string without any further
11 | // escaping.
12 | //
13 | // All values are true except for the ASCII control characters (0-31), the
14 | // double quote ("), and the backslash character ("\").
15 | var safeSet = [utf8.RuneSelf]bool{
16 | ' ': true,
17 | '!': true,
18 | '"': false,
19 | '#': true,
20 | '$': true,
21 | '%': true,
22 | '&': true,
23 | '\'': true,
24 | '(': true,
25 | ')': true,
26 | '*': true,
27 | '+': true,
28 | ',': true,
29 | '-': true,
30 | '.': true,
31 | '/': true,
32 | '0': true,
33 | '1': true,
34 | '2': true,
35 | '3': true,
36 | '4': true,
37 | '5': true,
38 | '6': true,
39 | '7': true,
40 | '8': true,
41 | '9': true,
42 | ':': true,
43 | ';': true,
44 | '<': true,
45 | '=': true,
46 | '>': true,
47 | '?': true,
48 | '@': true,
49 | 'A': true,
50 | 'B': true,
51 | 'C': true,
52 | 'D': true,
53 | 'E': true,
54 | 'F': true,
55 | 'G': true,
56 | 'H': true,
57 | 'I': true,
58 | 'J': true,
59 | 'K': true,
60 | 'L': true,
61 | 'M': true,
62 | 'N': true,
63 | 'O': true,
64 | 'P': true,
65 | 'Q': true,
66 | 'R': true,
67 | 'S': true,
68 | 'T': true,
69 | 'U': true,
70 | 'V': true,
71 | 'W': true,
72 | 'X': true,
73 | 'Y': true,
74 | 'Z': true,
75 | '[': true,
76 | '\\': false,
77 | ']': true,
78 | '^': true,
79 | '_': true,
80 | '`': true,
81 | 'a': true,
82 | 'b': true,
83 | 'c': true,
84 | 'd': true,
85 | 'e': true,
86 | 'f': true,
87 | 'g': true,
88 | 'h': true,
89 | 'i': true,
90 | 'j': true,
91 | 'k': true,
92 | 'l': true,
93 | 'm': true,
94 | 'n': true,
95 | 'o': true,
96 | 'p': true,
97 | 'q': true,
98 | 'r': true,
99 | 's': true,
100 | 't': true,
101 | 'u': true,
102 | 'v': true,
103 | 'w': true,
104 | 'x': true,
105 | 'y': true,
106 | 'z': true,
107 | '{': true,
108 | '|': true,
109 | '}': true,
110 | '~': true,
111 | '\u007f': true,
112 | }
113 |
114 | // htmlSafeSet holds the value true if the ASCII character with the given
115 | // array position can be safely represented inside a JSON string, embedded
116 | // inside of HTML