Something went wrong. Try again.
Approval-based snapshot testing library for Go (mirror)
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128package transform
import ( "encoding/json" "fmt")
// Scrubber transforms content before snapshotting.type Scrubber interface { Scrub(content string) string}
// IgnorePattern determines whether a key-value pair should be excluded.type IgnorePattern interface { ShouldIgnore(key, value string) bool}
// Config holds the transformation configuration.type Config struct { Scrubbers []Scrubber Ignore []IgnorePattern}
// ApplyScrubbers applies all scrubbers to the content in order.func ApplyScrubbers(content string, scrubbers []Scrubber) string { result := content for _, scrubber := range scrubbers { result = scrubber.Scrub(result) } return result}
// TransformJSON applies scrubbers and ignore patterns to JSON data.func TransformJSON(jsonStr string, config *Config) (string, error) { var data any if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { return "", fmt.Errorf("failed to unmarshal JSON: %w", err) }
// Apply ignore patterns first (removes fields) if len(config.Ignore) > 0 { data = walkAndFilter(data, config.Ignore) }
// Marshal back to JSON prettyJSON, err := json.MarshalIndent(data, "", " ") if err != nil { return "", fmt.Errorf("failed to marshal JSON: %w", err) }
result := string(prettyJSON)
// Apply scrubbers to the final string result = ApplyScrubbers(result, config.Scrubbers)
return result, nil}
// walkAndFilter recursively walks the data structure and filters out ignored fields.func walkAndFilter(data any, ignorePatterns []IgnorePattern) any { switch v := data.(type) { case map[string]any: return filterMap(v, ignorePatterns) case []any: return filterSlice(v, ignorePatterns) default: return data }}
// filterMap filters a map, removing entries that match ignore patterns.func filterMap(m map[string]any, ignorePatterns []IgnorePattern) map[string]any { result := make(map[string]any) for key, value := range m { // Convert value to string for comparison valueStr := valueToString(value)
// Check if this key-value pair should be ignored shouldIgnore := false for _, pattern := range ignorePatterns { if pattern.ShouldIgnore(key, valueStr) { shouldIgnore = true break } }
if !shouldIgnore { // Recursively filter nested structures result[key] = walkAndFilter(value, ignorePatterns) } } return result}
// filterSlice filters a slice, recursively processing each element.func filterSlice(s []any, ignorePatterns []IgnorePattern) []any { result := make([]any, len(s)) for i, item := range s { result[i] = walkAndFilter(item, ignorePatterns) } return result}
// valueToString converts various value types to string for comparison.func valueToString(value any) string { switch v := value.(type) { case string: return v case nil: return "null" case bool: if v { return "true" } return "false" case float64: return fmt.Sprintf("%v", v) case int, int64: return fmt.Sprintf("%d", v) default: // For complex types, marshal to JSON if bytes, err := json.Marshal(v); err == nil { return string(bytes) } return fmt.Sprintf("%v", v) }}