package processing import ( "bytes" "encoding/json" ) // v1ProcessItemKeyOrder is the human-readable LegacyProcessItem property order. // Important catalog fields first; internal ids / SEO last. var v1ProcessItemKeyOrder = []string{ "ean", "title", "name", "category", "category_id", "category_name", "description", "attributes", "main_image", "more_images", "eprel", "status", "error", "meta_title", "meta_description", "id", "processed_product_id", "raw_product_id", } // MarshalJSON emits LegacyProcessItem keys in a stable human-readable order. // ASSUMPTION: JSON object key order is part of the V1 readability contract for A1. func (item V1ProcessJobItem) MarshalJSON() ([]byte, error) { if item == nil { return []byte("null"), nil } var buf bytes.Buffer buf.WriteByte('{') first := true writePair := func(k string, v any) error { if !first { buf.WriteByte(',') } first = false kb, err := json.Marshal(k) if err != nil { return err } vb, err := json.Marshal(v) if err != nil { return err } buf.Write(kb) buf.WriteByte(':') buf.Write(vb) return nil } seen := map[string]struct{}{} for _, k := range v1ProcessItemKeyOrder { v, ok := item[k] if !ok { continue } seen[k] = struct{}{} if err := writePair(k, v); err != nil { return nil, err } } // Preserve any unexpected keys deterministically (sorted via encoding/json map). extras := map[string]any{} for k, v := range item { if _, ok := seen[k]; ok { continue } extras[k] = v } if len(extras) > 0 { eb, err := json.Marshal(extras) if err != nil { return nil, err } // eb is `{...}`; splice inner pairs. inner := bytes.TrimSpace(eb) if len(inner) >= 2 && inner[0] == '{' && inner[len(inner)-1] == '}' { inner = inner[1 : len(inner)-1] if len(bytes.TrimSpace(inner)) > 0 { if !first { buf.WriteByte(',') } first = false buf.Write(inner) } } } buf.WriteByte('}') return buf.Bytes(), nil }