Skip to content

Commit 29fadc8

Browse files
committed
Seems solid
1 parent 504fb7c commit 29fadc8

File tree

2 files changed

+44
-5
lines changed

2 files changed

+44
-5
lines changed

plugins/code-link/src/api.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,32 @@ describe("CodeFilesAPI", () => {
336336
expect(trackerRemember).not.toHaveBeenCalled()
337337
})
338338

339+
it("seeds snapshot before a remote rename finishes to avoid echoing subscription updates", async () => {
340+
const { api, socket, tracker, trackerRemember } = setup()
341+
const content = "export const Old = 1"
342+
const existing = createCodeFile({ name: "Old.tsx", content })
343+
344+
await publishSnapshotAndClear({
345+
api,
346+
socket,
347+
files: [createCodeFile({ name: "Old.tsx", content })],
348+
})
349+
350+
framerMock.getCodeFiles.mockResolvedValueOnce([existing])
351+
existing.rename.mockImplementation(async (nextName: string) => {
352+
existing.name = nextName
353+
framerMock.getCodeFiles.mockResolvedValue([existing])
354+
await api.handleFramerFilesChanged(socket as unknown as WebSocket, tracker)
355+
})
356+
357+
await expect(api.applyRemoteRename("Old.tsx", "New", socket as unknown as WebSocket)).resolves.toBe(true)
358+
359+
const sentMessages = getSentMessages(socket)
360+
expect(sentMessages).toHaveLength(1)
361+
expectFileSyncedMessage(sentMessages[0], "New.tsx")
362+
expect(trackerRemember).not.toHaveBeenCalled()
363+
})
364+
339365
it("finds an extensionless rename source using its normalized name", async () => {
340366
const { api, socket, tracker, trackerRemember } = setup()
341367
const content = "export const Old = 1"

plugins/code-link/src/api.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,16 @@ export class CodeFilesAPI {
209209
return false
210210
}
211211

212+
const previousSourceSnapshot = this.lastSnapshot.get(sourceFileName)
213+
const previousTargetSnapshot = this.lastSnapshot.get(targetFileName)
214+
const renamedContent = previousSourceSnapshot ?? existing.content
215+
216+
// Update snapshot BEFORE rename to prevent race with file subscription.
217+
this.lastSnapshot.delete(sourceFileName)
218+
this.lastSnapshot.set(targetFileName, renamedContent)
219+
212220
try {
213221
await existing.rename(targetFileName)
214-
const content = this.lastSnapshot.get(sourceFileName)
215-
if (content !== undefined) {
216-
this.lastSnapshot.delete(sourceFileName)
217-
this.lastSnapshot.set(targetFileName, content)
218-
}
219222
socket.send(
220223
JSON.stringify({
221224
type: "file-synced",
@@ -225,6 +228,16 @@ export class CodeFilesAPI {
225228
)
226229
return true
227230
} catch (err) {
231+
if (previousSourceSnapshot !== undefined) {
232+
this.lastSnapshot.set(sourceFileName, previousSourceSnapshot)
233+
}
234+
235+
if (previousTargetSnapshot !== undefined) {
236+
this.lastSnapshot.set(targetFileName, previousTargetSnapshot)
237+
} else {
238+
this.lastSnapshot.delete(targetFileName)
239+
}
240+
228241
const message = `Failed to rename ${oldFileName} -> ${newFileName}`
229242
log.error(message, err)
230243
socket.send(

0 commit comments

Comments
 (0)