├── 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