Skip to content

Commit 0e6f704

Browse files
committed
fixing engine handling of multiple changes
1 parent fe024b4 commit 0e6f704

File tree

1 file changed

+98
-36
lines changed

1 file changed

+98
-36
lines changed

src/server.js

Lines changed: 98 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,29 @@ function applyTextChanges(fileContent, changes) {
148148
function applyPatternChanges(fileContent, changes) {
149149
let modifiedContent = fileContent;
150150

151+
// Detect potential conflicts by checking for duplicate find patterns
152+
const findPatterns = new Map();
153+
changes.forEach((change, index) => {
154+
if (change.find) {
155+
if (findPatterns.has(change.find)) {
156+
const existingIndex = findPatterns.get(change.find);
157+
console.warn(
158+
`\x1b[33m⚠ CONFLICT DETECTED: Multiple changes target the same pattern\x1b[0m`
159+
);
160+
console.warn(
161+
` Change ${existingIndex + 1}: ${changes[existingIndex].explanation}`
162+
);
163+
console.warn(` Change ${index + 1}: ${change.explanation}`);
164+
console.warn(` Pattern: ${change.find.substring(0, 100)}...`);
165+
console.warn(
166+
`\x1b[33m → Only the first change will be applied\x1b[0m`
167+
);
168+
} else {
169+
findPatterns.set(change.find, index);
170+
}
171+
}
172+
});
173+
151174
for (const change of changes) {
152175
const { type, find, replaceWith, insert, explanation } = change;
153176

@@ -157,12 +180,31 @@ function applyPatternChanges(fileContent, changes) {
157180
case "replace":
158181
if (find && replaceWith !== undefined) {
159182
if (modifiedContent.includes(find)) {
183+
// Check if replaceWith contains malformed JSX
184+
const openTags = (replaceWith.match(/<[^\/][^>]*>/g) || []).length;
185+
const closeTags = (replaceWith.match(/<\/[^>]*>/g) || []).length;
186+
187+
if (openTags !== closeTags) {
188+
console.warn(
189+
`\x1b[33m⚠ POTENTIAL JSX MALFORMATION: Unmatched tags in replacement\x1b[0m`
190+
);
191+
console.warn(
192+
` Open tags: ${openTags}, Close tags: ${closeTags}`
193+
);
194+
console.warn(
195+
` Replacement: ${replaceWith.substring(0, 200)}...`
196+
);
197+
}
198+
160199
modifiedContent = modifiedContent.replace(find, replaceWith);
161200
console.log(`\x1b[32m✓ Replaced pattern successfully\x1b[0m`);
162201
} else {
163202
console.warn(
164203
`\x1b[33m⚠ Pattern not found for replace: ${find.substring(0, 50)}...\x1b[0m`
165204
);
205+
console.warn(
206+
`\x1b[33m This might be due to a previous change modifying the content\x1b[0m`
207+
);
166208
}
167209
} else {
168210
console.warn("Invalid 'replace' change object:", change);
@@ -729,6 +771,7 @@ function createApp() {
729771
`\x1b[36mℹ Visual Editor API Request: Received ${changes.length} changes for repo ${github_repo_name}\x1b[0m`
730772
);
731773

774+
// Group changes by file to eliminate duplication
732775
const changesByFile = new Map();
733776
for (const change of changes) {
734777
try {
@@ -738,6 +781,7 @@ function createApp() {
738781
);
739782
continue;
740783
}
784+
741785
const encodedFilePath = change.encoded_location.split(":")[0];
742786
const targetFile = decode(encodedFilePath);
743787
if (!targetFile) {
@@ -746,13 +790,40 @@ function createApp() {
746790
);
747791
continue;
748792
}
793+
794+
// Initialize file entry if not exists
749795
if (!changesByFile.has(targetFile)) {
750-
changesByFile.set(targetFile, []);
796+
changesByFile.set(targetFile, {
797+
encoded_location: change.encoded_location,
798+
file_content: null, // Will be set below
799+
changes: [],
800+
});
801+
}
802+
803+
// Add this element change to the file
804+
const elementChange = {
805+
style_changes: change.style_changes || [],
806+
text_changes: [],
807+
};
808+
809+
// Create text_changes from old_html/new_html if present
810+
if (change.old_html !== undefined && change.new_html !== undefined) {
811+
elementChange.text_changes.push({
812+
old_text: change.old_html,
813+
new_text: change.new_html,
814+
});
815+
}
816+
817+
// Only add the change if it has actual content
818+
if (
819+
elementChange.style_changes.length > 0 ||
820+
elementChange.text_changes.length > 0
821+
) {
822+
changesByFile.get(targetFile).changes.push(elementChange);
751823
}
752-
changesByFile.get(targetFile).push(change);
753824
} catch (e) {
754825
console.error(
755-
`\x1b[31m✖ Error decoding location: ${change.encoded_location}\x1b[0m`
826+
`\x1b[31m✖ Error processing change for location: ${change.encoded_location}\x1b[0m`
756827
);
757828
}
758829
}
@@ -764,51 +835,42 @@ function createApp() {
764835
}
765836
}
766837

767-
const fileDataPromises = Array.from(changesByFile.entries()).map(
768-
async ([targetFile, fileChanges]) => {
838+
// Read file content for each file and create the grouped structure
839+
const fileChangesForBackend = [];
840+
for (const [targetFile, fileData] of changesByFile.entries()) {
841+
try {
842+
// Read file content once per file
769843
const { fileContent } = readFileFromEncodedLocation(
770-
fileChanges[0].encoded_location
844+
fileData.encoded_location
845+
);
846+
fileData.file_content = fileContent;
847+
848+
// Only include files that have actual changes
849+
if (fileData.changes.length > 0) {
850+
fileChangesForBackend.push({
851+
encoded_location: fileData.encoded_location,
852+
file_content: fileData.file_content,
853+
changes: fileData.changes,
854+
});
855+
}
856+
} catch (error) {
857+
console.error(
858+
`\x1b[31m✖ Error reading file content for ${targetFile}: ${error.message}\x1b[0m`
771859
);
772-
return {
773-
encoded_location: fileChanges[0].encoded_location,
774-
file_content: fileContent,
775-
style_changes: fileChanges.flatMap((c) => c.style_changes || []),
776-
text_changes: fileChanges
777-
.filter((c) => c.old_html !== undefined)
778-
.map((change) => ({
779-
...change,
780-
old_text: change.old_html,
781-
new_text: change.new_html,
782-
})),
783-
targetFile: targetFile,
784-
};
785860
}
786-
);
787-
788-
const fileDataForBackend = (await Promise.all(fileDataPromises)).filter(
789-
(f) => f.style_changes.length > 0 || f.text_changes.length > 0
790-
);
861+
}
791862

792-
if (fileDataForBackend.length === 0) {
863+
if (fileChangesForBackend.length === 0) {
793864
return reply.code(200).send({
794865
message: "No changes to apply.",
795866
updatedFiles: [],
796867
});
797868
}
798869

799870
console.log(
800-
`\x1b[36mℹ Preparing bulk request for ${fileDataForBackend.length} files.\x1b[0m`
871+
`\x1b[36mℹ Sending grouped request for ${fileChangesForBackend.length} files with ${changes.length} total changes\x1b[0m`
801872
);
802873

803-
const fileChangesForBackend = fileDataForBackend.map((f) => {
804-
return {
805-
encoded_location: f.encoded_location,
806-
file_content: f.file_content,
807-
style_changes: f.style_changes,
808-
text_changes: f.text_changes,
809-
};
810-
});
811-
812874
const backendResponse = await getChanges({
813875
githubRepoName: github_repo_name,
814876
fileChanges: fileChangesForBackend,
@@ -840,7 +902,7 @@ function createApp() {
840902
return reply.code(200).send({
841903
message: `Changes applied successfully to ${
842904
updatedFiles.size
843-
} file(s).`,
905+
} file(s). Processed ${changes.length} individual changes across ${fileChangesForBackend.length} files.`,
844906
updatedFiles: Array.from(updatedFiles),
845907
});
846908
} catch (err) {

0 commit comments

Comments
 (0)