Clean up the cringe
This commit is contained in:
@@ -89,11 +89,10 @@ func ProcessJSON(content string, command utils.ModifyCommand, filename string) (
|
|||||||
return commands, fmt.Errorf("failed to convert Lua table back to Go: %v", err)
|
return commands, fmt.Errorf("failed to convert Lua table back to Go: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use surgical JSON editing instead of full replacement
|
commands, err = applyJSONChanges(content, jsonData, goData)
|
||||||
commands, err = applySurgicalJSONChanges(content, jsonData, goData)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
processJsonLogger.Error("Failed to apply surgical JSON changes: %v", err)
|
processJsonLogger.Error("Failed to apply JSON changes: %v", err)
|
||||||
return commands, fmt.Errorf("failed to apply surgical JSON changes: %v", err)
|
return commands, fmt.Errorf("failed to apply JSON changes: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
processJsonLogger.Debug("Total JSON processing time: %v", time.Since(startTime))
|
processJsonLogger.Debug("Total JSON processing time: %v", time.Since(startTime))
|
||||||
@@ -101,8 +100,7 @@ func ProcessJSON(content string, command utils.ModifyCommand, filename string) (
|
|||||||
return commands, nil
|
return commands, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// applySurgicalJSONChanges compares original and modified data and applies changes surgically
|
func applyJSONChanges(content string, originalData, modifiedData interface{}) ([]utils.ReplaceCommand, error) {
|
||||||
func applySurgicalJSONChanges(content string, originalData, modifiedData interface{}) ([]utils.ReplaceCommand, error) {
|
|
||||||
var commands []utils.ReplaceCommand
|
var commands []utils.ReplaceCommand
|
||||||
|
|
||||||
// Convert both to JSON for comparison
|
// Convert both to JSON for comparison
|
||||||
@@ -121,25 +119,23 @@ func applySurgicalJSONChanges(content string, originalData, modifiedData interfa
|
|||||||
return commands, nil
|
return commands, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ALWAYS try surgical approach first - never fall back to full replacement
|
appliedCommands, err := applyChanges(content, originalData, modifiedData)
|
||||||
// This ensures field order is always preserved
|
if err == nil && len(appliedCommands) > 0 {
|
||||||
surgicalCommands, err := applyTrueSurgicalChanges(content, originalData, modifiedData)
|
return appliedCommands, nil
|
||||||
if err == nil && len(surgicalCommands) > 0 {
|
|
||||||
return surgicalCommands, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If surgical approach fails or finds no changes, something is wrong
|
return commands, fmt.Errorf("failed to make any changes to the json")
|
||||||
// This should not happen if there are actual changes
|
|
||||||
return commands, fmt.Errorf("surgical approach failed but changes detected")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// applyTrueSurgicalChanges attempts to make surgical changes while preserving exact formatting
|
// applyChanges attempts to make surgical changes while preserving exact formatting
|
||||||
func applyTrueSurgicalChanges(content string, originalData, modifiedData interface{}) ([]utils.ReplaceCommand, error) {
|
func applyChanges(content string, originalData, modifiedData interface{}) ([]utils.ReplaceCommand, error) {
|
||||||
var commands []utils.ReplaceCommand
|
var commands []utils.ReplaceCommand
|
||||||
|
|
||||||
// Find all changes between original and modified data
|
// Find all changes between original and modified data
|
||||||
changes := findDeepChanges("", originalData, modifiedData)
|
changes := findDeepChanges("", originalData, modifiedData)
|
||||||
|
|
||||||
|
fmt.Printf("DEBUG: Found %d changes: %v\n", len(changes), changes)
|
||||||
|
|
||||||
if len(changes) == 0 {
|
if len(changes) == 0 {
|
||||||
return commands, nil
|
return commands, nil
|
||||||
}
|
}
|
||||||
@@ -169,27 +165,21 @@ func applyTrueSurgicalChanges(content string, originalData, modifiedData interfa
|
|||||||
actualPath := strings.TrimSuffix(removalPath, "@remove")
|
actualPath := strings.TrimSuffix(removalPath, "@remove")
|
||||||
index := extractIndexFromRemovalPath(removalPath)
|
index := extractIndexFromRemovalPath(removalPath)
|
||||||
arrayPath := getArrayPathFromElementPath(actualPath)
|
arrayPath := getArrayPathFromElementPath(actualPath)
|
||||||
|
|
||||||
fmt.Printf("DEBUG: Removing element at path '%s' (index %d, array path '%s')\n", actualPath, index, arrayPath)
|
|
||||||
|
|
||||||
// Get the array element to remove
|
// Get the array element to remove
|
||||||
result := gjson.Get(content, actualPath)
|
result := gjson.Get(content, actualPath)
|
||||||
if !result.Exists() {
|
if !result.Exists() {
|
||||||
fmt.Printf("DEBUG: Element does not exist\n")
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the exact byte range to remove (including comma/formatting)
|
// Find the exact byte range to remove (including comma/formatting)
|
||||||
startPos, endPos := findArrayElementRemovalRange(content, arrayPath, index)
|
startPos, endPos := findArrayElementRemovalRange(content, arrayPath, index)
|
||||||
if startPos >= 0 && endPos > startPos {
|
if startPos >= 0 && endPos > startPos {
|
||||||
fmt.Printf("DEBUG: Removing bytes %d-%d: %q\n", startPos, endPos, content[startPos:endPos])
|
|
||||||
commands = append(commands, utils.ReplaceCommand{
|
commands = append(commands, utils.ReplaceCommand{
|
||||||
From: startPos,
|
From: startPos,
|
||||||
To: endPos,
|
To: endPos,
|
||||||
With: "", // Remove the element
|
With: "", // Remove the element
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
fmt.Printf("DEBUG: Invalid range %d-%d\n", startPos, endPos)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,22 +19,22 @@ func TestProcessJSON(t *testing.T) {
|
|||||||
name: "Basic JSON object modification",
|
name: "Basic JSON object modification",
|
||||||
input: `{"name": "test", "value": 42}`,
|
input: `{"name": "test", "value": 42}`,
|
||||||
luaExpression: `data.value = data.value * 2; return true`,
|
luaExpression: `data.value = data.value * 2; return true`,
|
||||||
expectedOutput: `{"name": "test", "value": 84}`, // Surgical editing preserves compact format
|
expectedOutput: `{"name": "test", "value": 84}`,
|
||||||
expectedMods: 1,
|
expectedMods: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "JSON array modification",
|
name: "JSON array modification",
|
||||||
input: `{"items": [{"id": 1, "value": 10}, {"id": 2, "value": 20}]}`,
|
input: `{"items": [{"name": "item1", "value": 10}, {"name": "item2", "value": 20}]}`,
|
||||||
luaExpression: `for i, item in ipairs(data.items) do data.items[i].value = item.value * 1.5 end; return true`,
|
luaExpression: `for i, item in ipairs(data.items) do item.value = item.value * 2 end modified = true`,
|
||||||
expectedOutput: `{"items": [{"id": 1, "value": 15}, {"id": 2, "value": 30}]}`, // Surgical editing preserves compact format
|
expectedOutput: `{"items": [{"name": "item1", "value": 20}, {"name": "item2", "value": 40}]}`,
|
||||||
expectedMods: 1,
|
expectedMods: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "JSON nested object modification",
|
name: "JSON nested object modification",
|
||||||
input: `{"config": {"settings": {"enabled": false, "timeout": 30}}}`,
|
input: `{"config": {"setting1": {"enabled": true, "value": 5}, "setting2": {"enabled": false, "value": 10}}}`,
|
||||||
luaExpression: `data.config.settings.enabled = true; data.config.settings.timeout = 60; return true`,
|
luaExpression: `data.config.setting1.enabled = false data.config.setting2.value = 15 modified = true`,
|
||||||
expectedOutput: `{"config": {"settings": {"enabled": true, "timeout": 60}}}`, // Surgical editing preserves compact format
|
expectedOutput: `{"config": {"setting1": {"enabled": false, "value": 5}, "setting2": {"enabled": false, "value": 15}}}`,
|
||||||
expectedMods: 1,
|
expectedMods: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "JSON no modification",
|
name: "JSON no modification",
|
||||||
|
@@ -11,6 +11,7 @@ func TestSurgicalJSONEditing(t *testing.T) {
|
|||||||
content string
|
content string
|
||||||
luaCode string
|
luaCode string
|
||||||
expected string
|
expected string
|
||||||
|
skip bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Modify single field",
|
name: "Modify single field",
|
||||||
@@ -42,7 +43,7 @@ modified = true
|
|||||||
expected: `{
|
expected: `{
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"value": 42
|
"value": 42
|
||||||
,"newField":"added"}`, // sjson.Set() adds new fields in compact format
|
,"newField":"added"}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Modify nested field",
|
name: "Modify nested field",
|
||||||
@@ -72,6 +73,9 @@ modified = true
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.skip {
|
||||||
|
t.Skip("Skipping test due to surgical approach not handling this case yet")
|
||||||
|
}
|
||||||
command := utils.ModifyCommand{
|
command := utils.ModifyCommand{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Lua: tt.luaCode,
|
Lua: tt.luaCode,
|
||||||
|
Reference in New Issue
Block a user