diff --git a/processor/json.go b/processor/json.go index 4b4e9c1..6c2e379 100644 --- a/processor/json.go +++ b/processor/json.go @@ -89,7 +89,7 @@ func ProcessJSON(content string, command utils.ModifyCommand, filename string) ( return commands, fmt.Errorf("failed to convert Lua table back to Go: %v", err) } - commands, err = applySurgicalJSONChanges(content, jsonData, goData) + commands, err = applyJSONChanges(content, jsonData, goData) if err != nil { processJsonLogger.Error("Failed to apply JSON changes: %v", err) return commands, fmt.Errorf("failed to apply JSON changes: %v", err) @@ -100,35 +100,36 @@ func ProcessJSON(content string, command utils.ModifyCommand, filename string) ( return commands, nil } -// applySurgicalJSONChanges compares original and modified data and applies changes surgically -func applySurgicalJSONChanges(content string, originalData, modifiedData interface{}) ([]utils.ReplaceCommand, error) { +// applyJSONChanges compares original and modified data and applies changes surgically +func applyJSONChanges(content string, originalData, modifiedData interface{}) ([]utils.ReplaceCommand, error) { var commands []utils.ReplaceCommand - - // Apply surgical changes + appliedCommands, err := applyChanges(content, originalData, modifiedData) if err == nil && len(appliedCommands) > 0 { return appliedCommands, nil } - + return commands, fmt.Errorf("failed to make any changes to the json") } // applyChanges attempts to make surgical changes while preserving exact formatting func applyChanges(content string, originalData, modifiedData interface{}) ([]utils.ReplaceCommand, error) { var commands []utils.ReplaceCommand - + // Find all changes between original and modified data changes := findDeepChanges("", originalData, modifiedData) - + + jsonLogger.Debug("applyChanges: Found %d changes: %v", len(changes), changes) + if len(changes) == 0 { return commands, nil } - + // Sort removal operations by index in descending order to avoid index shifting var removals []string var additions []string var valueChanges []string - + for path := range changes { if strings.HasSuffix(path, "@remove") { removals = append(removals, path) @@ -138,23 +139,21 @@ func applyChanges(content string, originalData, modifiedData interface{}) ([]uti valueChanges = append(valueChanges, path) } } - - jsonLogger.Info("applyChanges: Found %d changes: %v", len(changes), changes) - - jsonLogger.Info("applyChanges: %d removals, %d additions, %d value changes", len(removals), len(additions), len(valueChanges)) - + + jsonLogger.Debug("applyChanges: %d removals, %d additions, %d value changes", len(removals), len(additions), len(valueChanges)) + // Apply removals first (from end to beginning to avoid index shifting) for _, removalPath := range removals { actualPath := strings.TrimSuffix(removalPath, "@remove") index := extractIndexFromRemovalPath(removalPath) arrayPath := getArrayPathFromElementPath(actualPath) - + // Get the array element to remove result := gjson.Get(content, actualPath) if !result.Exists() { continue } - + // Find the exact byte range to remove (including comma/formatting) startPos, endPos := findArrayElementRemovalRange(content, arrayPath, index) if startPos >= 0 && endPos > startPos { @@ -165,20 +164,20 @@ func applyChanges(content string, originalData, modifiedData interface{}) ([]uti }) } } - + // Apply additions (new fields) for _, additionPath := range additions { actualPath := strings.TrimSuffix(additionPath, "@add") newValue := changes[additionPath] - - jsonLogger.Info("Processing addition: path=%s, value=%v", actualPath, newValue) - + + jsonLogger.Debug("Processing addition: path=%s, value=%v", actualPath, newValue) + // Find the parent object to add the field to parentPath := getParentPath(actualPath) fieldName := getFieldName(actualPath) - - jsonLogger.Info("Parent path: %s, field name: %s", parentPath, fieldName) - + + jsonLogger.Debug("Parent path: %s, field name: %s", parentPath, fieldName) + // Get the parent object var parentResult gjson.Result if parentPath == "" { @@ -187,34 +186,34 @@ func applyChanges(content string, originalData, modifiedData interface{}) ([]uti } else { parentResult = gjson.Get(content, parentPath) } - + if !parentResult.Exists() { - jsonLogger.Info("Parent path %s does not exist, skipping", parentPath) + jsonLogger.Debug("Parent path %s does not exist, skipping", parentPath) continue } - + // Find where to insert the new field (at the end of the object) startPos := int(parentResult.Index + len(parentResult.Raw) - 1) // Before closing brace - - jsonLogger.Info("Inserting at pos %d", startPos) - + + jsonLogger.Debug("Inserting at pos %d", startPos) + // Convert the new value to JSON string newValueStr := convertValueToJSONString(newValue) - + // Insert the new field insertText := fmt.Sprintf(`,"%s":%s`, fieldName, newValueStr) - - jsonLogger.Info("Inserting text: %q", insertText) - + + jsonLogger.Debug("Inserting text: %q", insertText) + commands = append(commands, utils.ReplaceCommand{ From: startPos, To: startPos, With: insertText, }) - - jsonLogger.Info("Added addition command: From=%d, To=%d, With=%q", startPos, startPos, insertText) + + jsonLogger.Debug("Added addition command: From=%d, To=%d, With=%q", startPos, startPos, insertText) } - + // Apply value changes (in reverse order to avoid position shifting) sort.Slice(valueChanges, func(i, j int) bool { // Get positions for comparison @@ -222,40 +221,40 @@ func applyChanges(content string, originalData, modifiedData interface{}) ([]uti resultJ := gjson.Get(content, valueChanges[j]) return resultI.Index > resultJ.Index // Descending order }) - + for _, path := range valueChanges { newValue := changes[path] - - jsonLogger.Info("Processing value change: path=%s, value=%v", path, newValue) - + + jsonLogger.Debug("Processing value change: path=%s, value=%v", path, newValue) + // Get the current value and its position in the original JSON result := gjson.Get(content, path) if !result.Exists() { - jsonLogger.Info("Path %s does not exist, skipping", path) + jsonLogger.Debug("Path %s does not exist, skipping", path) continue // Skip if path doesn't exist } - + // Get the exact byte positions of this value startPos := result.Index endPos := startPos + len(result.Raw) - - jsonLogger.Info("Found value at pos %d-%d: %q", startPos, endPos, result.Raw) - + + jsonLogger.Debug("Found value at pos %d-%d: %q", startPos, endPos, result.Raw) + // Convert the new value to JSON string newValueStr := convertValueToJSONString(newValue) - - jsonLogger.Info("Converting to: %q", newValueStr) - + + jsonLogger.Debug("Converting to: %q", newValueStr) + // Create a replacement command for this specific value commands = append(commands, utils.ReplaceCommand{ From: int(startPos), To: int(endPos), With: newValueStr, }) - - jsonLogger.Info("Added command: From=%d, To=%d, With=%q", int(startPos), int(endPos), newValueStr) + + jsonLogger.Debug("Added command: From=%d, To=%d, With=%q", int(startPos), int(endPos), newValueStr) } - + return commands, nil } @@ -377,7 +376,7 @@ func findDeepChanges(basePath string, original, modified interface{}) map[string } else { currentPath = basePath + "." + key } - + if origValue, exists := orig[key]; exists { // Key exists in both, check if value changed switch modValue.(type) {