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

Function flexJSONToString

internal/models/item.go:825–876  ·  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

823// is supposed to add. The pre-existing ItemUpdate fields/tags path
824// inherits the same tightening because it routes through this helper.
825func flexJSONToString(raw json.RawMessage, expectedStart byte, errInvalid error) (*string, error) {
826 trimmed := bytes.TrimSpace(raw)
827 if len(trimmed) == 0 || bytes.Equal(trimmed, []byte("null")) {
828 return nil, nil
829 }
830 switch trimmed[0] {
831 case '"':
832 // JSON-encoded string envelope — unmarshal to the underlying Go
833 // string and then validate the inner content's shape matches
834 // expectedStart. Subsequent code that does
835 // json.Unmarshal([]byte(*s), ...) sees the inner JSON, not a
836 // re-quoted string.
837 var s string
838 if err := json.Unmarshal(trimmed, &s); err != nil {
839 return nil, errInvalid
840 }
841 // Empty inner string is the empty-string sentinel; store-layer
842 // coercion handles it (IDEA-1486). Don't reject here so callers
843 // retain the legacy "" → default normalization shape.
844 innerTrimmed := bytes.TrimSpace([]byte(s))
845 if len(innerTrimmed) == 0 {
846 return &s, nil
847 }
848 if innerTrimmed[0] != expectedStart {
849 return nil, errInvalid
850 }
851 // Confirm the inner content actually parses as JSON of the
852 // expected shape. Catches strings that start with the right
853 // brace but are otherwise garbage (e.g. `"{not valid"`).
854 var inner any
855 if err := json.Unmarshal(innerTrimmed, &inner); err != nil {
856 return nil, errInvalid
857 }
858 return &s, nil
859 case expectedStart:
860 // Object or array — re-marshal to a canonical JSON string so
861 // the downstream string-typed pipeline can json.Unmarshal it
862 // back to a map/slice exactly as if the caller had stringified.
863 var v any
864 if err := json.Unmarshal(trimmed, &v); err != nil {
865 return nil, errInvalid
866 }
867 b, err := json.Marshal(v)
868 if err != nil {
869 return nil, errInvalid
870 }
871 s := string(b)
872 return &s, nil
873 default:
874 return nil, errInvalid
875 }
876}
877
878type ItemListParams struct {
879 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