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.
active/core/errs/erjson/json_builder.go

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
}

Powered by TurnKey Linux.