mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-01-02 14:22:28 +08:00
feat: improve XML search/replace matching strategies (#129)
- Add 6th strategy: match by value attribute (label text) - Add 7th strategy: normalized whitespace match - Remove lastProcessedIndex tracking - always search from beginning - Pairs may not be in document order, so sequential tracking was unreliable Co-authored-by: dayuan.jiang <jiangdy@amazon.co.jp>
This commit is contained in:
86
lib/utils.ts
86
lib/utils.ts
@@ -226,7 +226,6 @@ export function replaceXMLParts(
|
|||||||
): string {
|
): string {
|
||||||
// Format the XML first to ensure consistent line breaks
|
// Format the XML first to ensure consistent line breaks
|
||||||
let result = formatXML(xmlContent)
|
let result = formatXML(xmlContent)
|
||||||
let lastProcessedIndex = 0
|
|
||||||
|
|
||||||
for (const { search, replace } of searchReplacePairs) {
|
for (const { search, replace } of searchReplacePairs) {
|
||||||
// Also format the search content for consistency
|
// Also format the search content for consistency
|
||||||
@@ -241,18 +240,10 @@ export function replaceXMLParts(
|
|||||||
searchLines.pop()
|
searchLines.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the line number where lastProcessedIndex falls
|
// Always search from the beginning - pairs may not be in document order
|
||||||
let startLineNum = 0
|
const startLineNum = 0
|
||||||
let currentIndex = 0
|
|
||||||
while (
|
|
||||||
currentIndex < lastProcessedIndex &&
|
|
||||||
startLineNum < resultLines.length
|
|
||||||
) {
|
|
||||||
currentIndex += resultLines[startLineNum].length + 1 // +1 for \n
|
|
||||||
startLineNum++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to find exact match starting from lastProcessedIndex
|
// Try to find match using multiple strategies
|
||||||
let matchFound = false
|
let matchFound = false
|
||||||
let matchStartLine = -1
|
let matchStartLine = -1
|
||||||
let matchEndLine = -1
|
let matchEndLine = -1
|
||||||
@@ -397,6 +388,71 @@ export function replaceXMLParts(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sixth try: Match by value attribute (label text)
|
||||||
|
// Extract value from search pattern and find elements with that value
|
||||||
|
if (!matchFound) {
|
||||||
|
const valueMatch = search.match(/value="([^"]*)"/)
|
||||||
|
if (valueMatch) {
|
||||||
|
const searchValue = valueMatch[0] // Use full match like value="text"
|
||||||
|
for (let i = startLineNum; i < resultLines.length; i++) {
|
||||||
|
if (resultLines[i].includes(searchValue)) {
|
||||||
|
// Found element with matching value
|
||||||
|
let endLine = i + 1
|
||||||
|
const line = resultLines[i].trim()
|
||||||
|
|
||||||
|
if (!line.endsWith("/>")) {
|
||||||
|
let depth = 1
|
||||||
|
while (endLine < resultLines.length && depth > 0) {
|
||||||
|
const currentLine = resultLines[endLine].trim()
|
||||||
|
if (
|
||||||
|
currentLine.startsWith("<") &&
|
||||||
|
!currentLine.startsWith("</") &&
|
||||||
|
!currentLine.endsWith("/>")
|
||||||
|
) {
|
||||||
|
depth++
|
||||||
|
} else if (currentLine.startsWith("</")) {
|
||||||
|
depth--
|
||||||
|
}
|
||||||
|
endLine++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
matchStartLine = i
|
||||||
|
matchEndLine = endLine
|
||||||
|
matchFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seventh try: Normalized whitespace match
|
||||||
|
// Collapse all whitespace and compare
|
||||||
|
if (!matchFound) {
|
||||||
|
const normalizeWs = (s: string) => s.replace(/\s+/g, " ").trim()
|
||||||
|
const normalizedSearch = normalizeWs(search)
|
||||||
|
|
||||||
|
for (
|
||||||
|
let i = startLineNum;
|
||||||
|
i <= resultLines.length - searchLines.length;
|
||||||
|
i++
|
||||||
|
) {
|
||||||
|
// Build a normalized version of the candidate lines
|
||||||
|
const candidateLines = resultLines.slice(
|
||||||
|
i,
|
||||||
|
i + searchLines.length,
|
||||||
|
)
|
||||||
|
const normalizedCandidate = normalizeWs(candidateLines.join(" "))
|
||||||
|
|
||||||
|
if (normalizedCandidate === normalizedSearch) {
|
||||||
|
matchStartLine = i
|
||||||
|
matchEndLine = i + searchLines.length
|
||||||
|
matchFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!matchFound) {
|
if (!matchFound) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Search pattern not found in the diagram. The pattern may not exist in the current structure.`,
|
`Search pattern not found in the diagram. The pattern may not exist in the current structure.`,
|
||||||
@@ -419,12 +475,6 @@ export function replaceXMLParts(
|
|||||||
]
|
]
|
||||||
|
|
||||||
result = newResultLines.join("\n")
|
result = newResultLines.join("\n")
|
||||||
|
|
||||||
// Update lastProcessedIndex to the position after the replacement
|
|
||||||
lastProcessedIndex = 0
|
|
||||||
for (let i = 0; i < matchStartLine + replaceLines.length; i++) {
|
|
||||||
lastProcessedIndex += newResultLines[i].length + 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
Reference in New Issue
Block a user