github.com/aergoio/aergo@v1.3.1/cmd/aergocli/util/encoding/json/indent.go (about) 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 }