MCPcopy Create free account
hub / github.com/PerpetualSoftware/pad / flexJSONToString

Function flexJSONToString

internal/models/item.go:755–806  ·  view source on GitHub ↗

flexJSONToString accepts a raw JSON value and returns it as a canonical JSON-encoded string. Acceptable inbound shapes: - absent / empty / null → nil (caller leaves the field unchanged) - JSON-encoded string whose INNER content is either empty (the legacy empty-string sentinel handled downstream by

(raw json.RawMessage, expectedStart byte, errInvalid error)

Source from the content-addressed store, hash-verified

753// is supposed to add. The pre-existing ItemUpdate fields/tags path
754// inherits the same tightening because it routes through this helper.
755func flexJSONToString(raw json.RawMessage, expectedStart byte, errInvalid error) (*string, error) {
756 trimmed := bytes.TrimSpace(raw)
757 if len(trimmed) == 0 || bytes.Equal(trimmed, []byte("null")) {
758 return nil, nil
759 }
760 switch trimmed[0] {
761 case '"':
762 // JSON-encoded string envelope — unmarshal to the underlying Go
763 // string and then validate the inner content's shape matches
764 // expectedStart. Subsequent code that does
765 // json.Unmarshal([]byte(*s), ...) sees the inner JSON, not a
766 // re-quoted string.
767 var s string
768 if err := json.Unmarshal(trimmed, &s); err != nil {
769 return nil, errInvalid
770 }
771 // Empty inner string is the empty-string sentinel; store-layer
772 // coercion handles it (IDEA-1486). Don't reject here so callers
773 // retain the legacy "" → default normalization shape.
774 innerTrimmed := bytes.TrimSpace([]byte(s))
775 if len(innerTrimmed) == 0 {
776 return &s, nil
777 }
778 if innerTrimmed[0] != expectedStart {
779 return nil, errInvalid
780 }
781 // Confirm the inner content actually parses as JSON of the
782 // expected shape. Catches strings that start with the right
783 // brace but are otherwise garbage (e.g. `"{not valid"`).
784 var inner any
785 if err := json.Unmarshal(innerTrimmed, &inner); err != nil {
786 return nil, errInvalid
787 }
788 return &s, nil
789 case expectedStart:
790 // Object or array — re-marshal to a canonical JSON string so
791 // the downstream string-typed pipeline can json.Unmarshal it
792 // back to a map/slice exactly as if the caller had stringified.
793 var v any
794 if err := json.Unmarshal(trimmed, &v); err != nil {
795 return nil, errInvalid
796 }
797 b, err := json.Marshal(v)
798 if err != nil {
799 return nil, errInvalid
800 }
801 s := string(b)
802 return &s, nil
803 default:
804 return nil, errInvalid
805 }
806}
807
808type ItemListParams struct {
809 CollectionSlug string

Callers 6

UnmarshalJSONMethod · 0.85
UnmarshalJSONMethod · 0.85
UnmarshalJSONMethod · 0.85
UnmarshalJSONMethod · 0.85
UnmarshalJSONMethod · 0.85
UnmarshalJSONMethod · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected