You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
7.6 KiB
390 lines
7.6 KiB
// ------------------------------------------------------------------------
|
|
// Project active2
|
|
// Active Thing (activething.com) git.activething.com/go
|
|
//
|
|
// File name text_builder.go
|
|
// Created by DEV
|
|
// Modified 20/04/2024
|
|
//
|
|
// Copyright 2024 activething.com
|
|
// ------------------------------------------------------------------------
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
// ------------------------------------------------------------------------
|
|
|
|
package erjson
|
|
|
|
import (
|
|
"codecs/cjson"
|
|
"encoding/json"
|
|
"errs/erdata"
|
|
"fmt"
|
|
"mems"
|
|
"strings"
|
|
)
|
|
|
|
|
|
type (
|
|
|
|
jsonBuilder struct {
|
|
f *JSONEncoder
|
|
b *mems.ABuffer
|
|
encoder *json.Encoder
|
|
sep string
|
|
pretty bool
|
|
invalid error
|
|
}
|
|
|
|
)
|
|
|
|
|
|
func newJsonBuilder (f *JSONEncoder) *jsonBuilder {
|
|
sep := ":"
|
|
if f.HasUseSpace() && f.HasShowPretty() {
|
|
sep = ": "
|
|
}
|
|
return &jsonBuilder{
|
|
f : f,
|
|
b : mems.NewABuffer(),
|
|
pretty : f.HasShowPretty(),
|
|
sep : sep,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (b *jsonBuilder) format (err error) {
|
|
cl := erdata.NewErrorData(err)
|
|
cl.Collect(b.f.HasAddFields(),b.f.HasAddCauses(),b.f.HasAddTrace())
|
|
|
|
if cl.Invalid != nil {
|
|
b.writeFormatError(cl.Invalid)
|
|
return
|
|
}
|
|
|
|
b.write(cl,false, 0)
|
|
}
|
|
|
|
|
|
func (b *jsonBuilder) write (coll *erdata.ErrorData, cont bool, level int) {
|
|
if b.invalid != nil {
|
|
return
|
|
}
|
|
|
|
d := false
|
|
defer func(dn *bool, bl *jsonBuilder){
|
|
if !(*dn) {
|
|
if rc := recover(); rc != nil {
|
|
if er,is := rc.(error); is {
|
|
bl.invalid = er
|
|
} else {
|
|
bl.invalid = fmt.Errorf("%#v",rc)
|
|
}
|
|
bl.writeFormatError(bl.invalid)
|
|
}
|
|
}
|
|
}(&d,b)
|
|
|
|
|
|
var (
|
|
indLvl,
|
|
indObj,
|
|
ind2Obj string
|
|
)
|
|
|
|
if b.pretty {
|
|
if level > 0 {
|
|
indLvl = strings.Repeat(b.f.layout.Indent, 1+level)
|
|
indObj = strings.Repeat(b.f.layout.Indent, 2+level)
|
|
ind2Obj = strings.Repeat(b.f.layout.Indent, 3+level)
|
|
} else {
|
|
indObj = b.f.layout.Indent
|
|
ind2Obj = strings.Repeat(b.f.layout.Indent,2)
|
|
}
|
|
if !cont {
|
|
b.b.WriteString(indLvl)
|
|
}
|
|
}
|
|
|
|
|
|
b.b.WriteByte('{')
|
|
if b.pretty {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
b.writeField(erdata.FieldNameError,coll.ErrStr, indObj,true,false, false)
|
|
|
|
|
|
if b.f.HasAddTypes() {
|
|
types := coll.Types
|
|
|
|
b.b.WriteByte(',')
|
|
if b.pretty {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
|
|
if len(types) == 1 {
|
|
b.writeField(erdata.FieldNameType, types[0].String(), indObj, true, false,false)
|
|
} else {
|
|
|
|
b.writeOpen(erdata.FieldNameTypes, indObj, '[', b.pretty)
|
|
for i, t := range coll.TypesStr {
|
|
if b.pretty {
|
|
b.b.WriteString(ind2Obj)
|
|
}
|
|
b.b.WriteByte('"')
|
|
b.b.WriteString(t)
|
|
b.b.WriteByte('"')
|
|
if i < len(coll.Types)-1 {
|
|
b.b.WriteByte(',')
|
|
}
|
|
if b.pretty {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
}
|
|
|
|
b.writeClose(indObj, ']')
|
|
}
|
|
}
|
|
|
|
|
|
heads := coll.Fields.GetHeads()
|
|
if len(heads) > 0 {
|
|
|
|
b.b.WriteByte(',')
|
|
if b.pretty {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
|
|
coll.Fields.Sort()
|
|
b.writeOpen(erdata.FieldNameFields, indObj, '{', b.pretty)
|
|
var n = 0
|
|
|
|
for _, h := range heads {
|
|
p := b.b.Len()
|
|
|
|
if n > 0 {
|
|
b.b.WriteByte(',')
|
|
if b.pretty {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
}
|
|
|
|
b.writeFieldName(h.Name,ind2Obj)
|
|
|
|
if !b.writeFieldValue(coll.Fields, h,level) {
|
|
b.b.Truncate(p)
|
|
continue
|
|
}
|
|
n++
|
|
}
|
|
if n > 0 && b.pretty {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
b.writeClose(indObj,'}')
|
|
}
|
|
|
|
causes := coll.Causes
|
|
if len (causes) > 0 {
|
|
|
|
b.b.WriteByte(',')
|
|
if b.pretty {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
|
|
if len(causes) == 1 {
|
|
b.writeOpen(erdata.FieldNameCause, indObj, 0, false)
|
|
b.write(&causes[0], true,level+1)
|
|
} else if len(causes) > 1 {
|
|
b.writeOpen(erdata.FieldNameCauses, indObj, '[', b.pretty)
|
|
for i, ce := range causes {
|
|
if i > 0 {
|
|
b.b.WriteByte(',')
|
|
if b.pretty {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
}
|
|
b.write(&ce, false,level+1)
|
|
}
|
|
if b.pretty {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
b.writeClose(indObj, ']')
|
|
}
|
|
}
|
|
|
|
|
|
if coll.Trace != nil {
|
|
p := b.b.Len()
|
|
|
|
b.b.WriteByte(',')
|
|
if b.pretty {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
b.writeFieldName(erdata.FieldNameTrace,indObj)
|
|
|
|
if b.encoder == nil {
|
|
b.encoder = json.NewEncoder(b.b)
|
|
}
|
|
if b.pretty {
|
|
b.encoder.SetIndent(strings.Repeat(b.f.layout.Indent,level+1),b.f.layout.Indent)
|
|
}
|
|
|
|
if er := b.encoder.Encode(coll.Trace.Frames()); er != nil {
|
|
b.b.Truncate(p)
|
|
}
|
|
}
|
|
|
|
if b.pretty {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
b.writeClose(indLvl,'}')
|
|
|
|
d= true
|
|
}
|
|
|
|
|
|
|
|
func (b *jsonBuilder) writeOpen(name, indent string, object byte,nl bool) {
|
|
b.writeFieldName(name,indent)
|
|
if object != 0 {
|
|
b.b.WriteByte(object)
|
|
}
|
|
if nl {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
}
|
|
|
|
func (b *jsonBuilder) writeClose(indent string, object byte) {
|
|
if b.pretty {
|
|
b.b.WriteString(indent)
|
|
}
|
|
b.b.WriteByte(object)
|
|
}
|
|
|
|
func (b *jsonBuilder) writeFieldName (name, indent string) {
|
|
if b.pretty {
|
|
b.b.WriteString(indent)
|
|
}
|
|
cjson.WriteString(b.b,name,true)
|
|
b.b.WriteString(b.sep)
|
|
}
|
|
|
|
func (b *jsonBuilder) writeField (name, value, indent string, quote, coma, nl bool) {
|
|
b.writeFieldName(name,indent)
|
|
if quote {
|
|
b.b.WriteByte('"')
|
|
}
|
|
b.b.WriteString(value)
|
|
if quote {
|
|
b.b.WriteByte('"')
|
|
}
|
|
if coma {
|
|
b.b.WriteByte(',')
|
|
}
|
|
if b.pretty && nl {
|
|
b.b.WriteByte('\n')
|
|
}
|
|
}
|
|
|
|
|
|
func (b *jsonBuilder) writeFieldValue (fields erdata.Fields, field *erdata.FieldHead, level int) bool {
|
|
switch field.Kind {
|
|
case erdata.FieldKindFloat:
|
|
n := fields.GetFieldValueFloat(field)
|
|
if n == 0 && b.f.HasIgnoreDefaults() {
|
|
|
|
return false
|
|
}
|
|
cjson.WriteFloat(b.b,n,64,b.f.HasUseQuote())
|
|
return true
|
|
|
|
case erdata.FieldKindInt:
|
|
n := fields.GetFieldValueInt(field)
|
|
if n == 0 && b.f.HasIgnoreDefaults() {
|
|
return false
|
|
}
|
|
cjson.WriteInt(b.b,int64(n),b.f.HasUseQuote())
|
|
return true
|
|
|
|
case erdata.FieldKindString:
|
|
s := fields.GetFieldValueString(field)
|
|
if len(s) == 0 && b.f.HasIgnoreDefaults() {
|
|
return false
|
|
}
|
|
cjson.WriteString(b.b,s,b.f.HasEscapeHTML())
|
|
return true
|
|
|
|
case erdata.FieldKindTime:
|
|
d := fields.GetFieldValueDate(field)
|
|
if d.IsZero() && b.f.HasIgnoreDefaults(){
|
|
return false
|
|
}
|
|
cjson.WriteDate(b.b,d,b.f.layout.TimeLayout,true)
|
|
return true
|
|
|
|
case erdata.FieldKindDate:
|
|
d := fields.GetFieldValueDate(field)
|
|
if d.IsZero() && b.f.HasIgnoreDefaults(){
|
|
return false
|
|
}
|
|
cjson.WriteDate(b.b,d,b.f.layout.DateLayout,true)
|
|
return true
|
|
|
|
case erdata.FieldKindBool:
|
|
t := fields.GetFieldValueBool(field)
|
|
if !t && b.f.HasIgnoreDefaults() {
|
|
return false
|
|
}
|
|
cjson.WriteBool(b.b,t,b.f.HasUseQuote())
|
|
return true
|
|
|
|
default:
|
|
a := fields.GetFieldValueAny(field)
|
|
if a == nil {
|
|
if b.f.HasIgnoreDefaults() {
|
|
return false
|
|
}
|
|
b.b.WOQ(true,'"',cjson.G.NullValue)
|
|
return true
|
|
}
|
|
|
|
if b.encoder == nil {
|
|
b.encoder = json.NewEncoder(b.b)
|
|
b.encoder.SetEscapeHTML(b.f.HasEscapeHTML())
|
|
}
|
|
|
|
if b.pretty {
|
|
b.encoder.SetIndent(strings.Repeat(b.f.layout.Indent,level+3),b.f.layout.Indent)
|
|
}
|
|
if er := b.encoder.Encode(a); er != nil {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
|
|
|
|
func (b *jsonBuilder) writeFormatError (err error) {
|
|
b.b.Reset()
|
|
b.b.WriteByte('{')
|
|
b.writeFieldName("json-formatter-error","")
|
|
cjson.WriteString(b.b,err.Error(),b.f.HasEscapeHTML())
|
|
b.b.WriteByte('}')
|
|
}
|
|
|
|
|
|
|
|
func (b *jsonBuilder) reset () {
|
|
b.b.Reset()
|
|
b.encoder = nil
|
|
b.invalid = nil
|
|
} |