refactor(gemini): optimize removeExtensionFields with post-order traversal and DeleteBytes

Amp-Thread-ID: https://ampcode.com/threads/T-019c0d09-330d-7399-b794-652b94847df1
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
이대희
2026-01-30 13:02:58 +09:00
parent d0d66cdcb7
commit ca796510e9

View File

@@ -4,6 +4,7 @@ package util
import ( import (
"fmt" "fmt"
"sort" "sort"
"strconv"
"strings" "strings"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
@@ -441,32 +442,43 @@ func removeUnsupportedKeywords(jsonStr string) string {
func removeExtensionFields(jsonStr string) string { func removeExtensionFields(jsonStr string) string {
var paths []string var paths []string
walkForExtensions(gjson.Parse(jsonStr), "", &paths) walkForExtensions(gjson.Parse(jsonStr), "", &paths)
sortByDepth(paths) // walkForExtensions returns paths in a way that deeper paths are added before their ancestors
// when they are not deleted wholesale, but since we skip children of deleted x-* nodes,
// any collected path is safe to delete. We still use DeleteBytes for efficiency.
b := []byte(jsonStr)
for _, p := range paths { for _, p := range paths {
jsonStr, _ = sjson.Delete(jsonStr, p) b, _ = sjson.DeleteBytes(b, p)
} }
return jsonStr return string(b)
} }
func walkForExtensions(value gjson.Result, path string, paths *[]string) { func walkForExtensions(value gjson.Result, path string, paths *[]string) {
if !value.IsObject() && !value.IsArray() { if value.IsArray() {
arr := value.Array()
for i := len(arr) - 1; i >= 0; i-- {
walkForExtensions(arr[i], joinPath(path, strconv.Itoa(i)), paths)
}
return return
} }
if value.IsObject() {
value.ForEach(func(key, val gjson.Result) bool { value.ForEach(func(key, val gjson.Result) bool {
keyStr := key.String() keyStr := key.String()
safeKey := escapeGJSONPathKey(keyStr) safeKey := escapeGJSONPathKey(keyStr)
childPath := joinPath(path, safeKey) childPath := joinPath(path, safeKey)
// Only remove x-* extension fields, but protect them if they are property definitions. // If it's an extension field, we delete it and don't need to look at its children.
if strings.HasPrefix(keyStr, "x-") && !isPropertyDefinition(path) { if strings.HasPrefix(keyStr, "x-") && !isPropertyDefinition(path) {
*paths = append(*paths, childPath) *paths = append(*paths, childPath)
return true
} }
walkForExtensions(val, childPath, paths) walkForExtensions(val, childPath, paths)
return true return true
}) })
} }
}
func cleanupRequiredFields(jsonStr string) string { func cleanupRequiredFields(jsonStr string) string {
for _, p := range findPaths(jsonStr, "required") { for _, p := range findPaths(jsonStr, "required") {