diff options
Diffstat (limited to 'reencode.go')
-rw-r--r-- | reencode.go | 56 |
1 files changed, 45 insertions, 11 deletions
diff --git a/reencode.go b/reencode.go index bcb3932..4c62cfc 100644 --- a/reencode.go +++ b/reencode.go @@ -18,13 +18,24 @@ type ReEncoder struct { AllowMultipleValues bool // Whether to minify the JSON. + // + // Trims all whitespace, except that it emits a newline + // between two *number* top-level values (or puts a newline + // after all top-level values if ForceTrailingNewlines). + // + // Trims superflous 0s from numbers. Compact bool // String to use to indent; ignored if Compact is true. + // + // Newlines are emitted *between* top-level values; a newline is + // not emitted after the *last* top-level value (unless + // ForceTrailingNewlines is on). Indent string // String to put before indents. Prefix string - // Whether to emit a newline after each top-level value, even - // if it could unambiguously be omitted. + // Whether to emit a newline after each top-level value. See + // the comments on Compact and Indent for discussion of how + // this is different than the usual behavior. ForceTrailingNewlines bool // Returns whether a given character in a string should be // backslash-escaped. The bool argument is whether it was @@ -46,6 +57,7 @@ type ReEncoder struct { // state: .handleRune lastNonSpace RuneType + wasNumber bool curIndent int uhex [4]byte // "\uABCD"-encoded characters in strings fracZeros int64 @@ -79,6 +91,10 @@ func (enc *ReEncoder) Write(p []byte) (int, error) { return len(p), nil } +// Close does what you'd expect, mostly. +// +// The *ReEncoder may continue to be written to with new JSON values +// if enc.AllowMultipleValues is set. func (enc *ReEncoder) Close() error { if enc.bufLen > 0 { return &ReEncodeSyntaxError{ @@ -93,7 +109,7 @@ func (enc *ReEncoder) Close() error { } return enc.err } - if err := enc.handleRune(0, 0); err != nil { + if err := enc.handleRune(0, RuneTypeError); err != nil { enc.err = &ReEncodeSyntaxError{ Err: err, Offset: enc.inputPos, @@ -159,6 +175,22 @@ func (enc *ReEncoder) handleRune(c rune, t RuneType) error { enc.lastNonSpace = t }() + // emit newlines between top-level values + if enc.lastNonSpace == RuneTypeEOF { + switch { + case enc.wasNumber && t.IsNumber(): + if err := enc.emitByte('\n'); err != nil { + return err + } + case enc.Indent != "" && !enc.Compact: + if err := enc.emitByte('\n'); err != nil { + return err + } + default: + // do nothing + } + } + // shorten numbers switch t { // trim trailing '0's from the fraction-part, but don't remove all digits case RuneTypeNumberFracDot: @@ -270,16 +302,18 @@ func (enc *ReEncoder) handleRune(c rune, t RuneType) error { rune(enc.uhex[3])<<0 return enc.emit(writeStringChar(enc.Out, c, BackslashEscapeUnicode, enc.BackslashEscape)) - case RuneTypeEOF: // start of next top-level value - if !enc.ForceTrailingNewlines && (enc.Compact || enc.Indent == "") && !enc.lastNonSpace.IsNumber() { - return nil - } - return enc.emitByte('\n') - case RuneTypeError: // .Close() - if !enc.ForceTrailingNewlines { + case RuneTypeError: // EOF explicitly stated by .Close() + fallthrough + case RuneTypeEOF: // EOF implied by the start of the next top-level value + enc.wasNumber = enc.lastNonSpace.IsNumber() + switch { + case enc.ForceTrailingNewlines: + t = RuneTypeError // enc.lastNonSpace : an NL isn't needed (we already printed one) + return enc.emitByte('\n') + default: + t = RuneTypeEOF // enc.lastNonSpace : an NL *might* be needed return nil } - return enc.emitByte('\n') default: return enc.emitByte(byte(c)) } |